pax_global_header00006660000000000000000000000064146656536700014534gustar00rootroot0000000000000052 comment=dae72c8b1142d0c3dd2a6784a78bc453ef28c46f linkchecker-10.5.0/000077500000000000000000000000001466565367000141015ustar00rootroot00000000000000linkchecker-10.5.0/.flake8000066400000000000000000000027711466565367000152630ustar00rootroot00000000000000[flake8] filename = *.py extend-exclude = build/ _LinkChecker_configdata.py # Derived from published packages linkcheck/better_exchook2.py linkcheck/colorama.py builtins = _ _n max-line-length = 88 per-file-ignores = # In several files imports intentionally cause: # E402: module level import not at top of file # F401: module imported but unused doc/src/conf.py: E402,F821 linkcheck/__init__.py: E402,F401 linkcheck/checker/httpurl.py: E402 linkcheck/htmlutil/htmlsoup.py: E402 linkcheck/parser/__init__.py: E402 tests/__init__.py: F401 # E501: line too long linkcheck/ftpparse.py: E501 linkcheck/checker/unknownurl.py: E501 linkcheck/command/arg_parser.py: E501 scripts/update_iana_uri_schemes.py: E501 tests/test_ftpparse.py: E501 # F821 undefined name # https://github.com/PyCQA/pyflakes/issues/548 linkcheck/logger/__init__.py: F821 extend-ignore = # https://pep8.readthedocs.org/en/latest/intro.html#error-codes # these are ignored by default: # E121: continuation line under-indented for hanging indent # E123: closing bracket does not match indentation of opening bracket’s line # E126: continuation line over-indented for hanging indent # E133: closing bracket does not match visual indentation # E226: missing whitespace around arithmetic operator # E241: multiple spaces after ‘,’ # E242: tab after ‘,’ # E704: multiple statements on one line (def) # W503: line break before binary operator # W504: line break after binary operator linkchecker-10.5.0/.git_archival.txt000066400000000000000000000001531466565367000173530ustar00rootroot00000000000000node: dae72c8b1142d0c3dd2a6784a78bc453ef28c46f node-date: 2024-09-03T19:38:48+01:00 describe-name: v10.5.0 linkchecker-10.5.0/.github/000077500000000000000000000000001466565367000154415ustar00rootroot00000000000000linkchecker-10.5.0/.github/ISSUE_TEMPLATE.md000066400000000000000000000026171466565367000201540ustar00rootroot00000000000000 ## Summary ## Steps to reproduce 1. 2. 3. ## Actual result ## Expected result ## Environment * Operating system: * Linkchecker version: * Python version: * Install method: ## Configuration ## Logs ## Other notes linkchecker-10.5.0/.github/workflows/000077500000000000000000000000001466565367000174765ustar00rootroot00000000000000linkchecker-10.5.0/.github/workflows/branch-man.yml000066400000000000000000000033611466565367000222320ustar00rootroot00000000000000name: Create a branch with updated man pages and application translations on: workflow_dispatch jobs: run: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v4 with: repository: linkchecker/linkchecker ref: master # Needed for hatch-vcs to extract LinkChecker version from tag # https://github.com/actions/checkout/issues/249 fetch-depth: 0 - name: Install Ubuntu packages run: sudo apt install gettext git - name: Setup Python uses: actions/setup-python@v5 with: python-version: "3.x" - name: Install Python packages run: > pip3 install dnspython beautifulsoup4 requests \ hatchling hatch-vcs sphinx sphinx_epytext \ sphinx_rtd_theme sphinx-sitemap sphinx-intl - name: Prepare git environment run: | git config user.email "linkchecker@linkchecker.github.io" git config user.name "LinkChecker" git checkout -b man-updates git remote add local ${{ github.server_url }}/${{ github.repository }} - name: Build man pages run: | python3 -m hatchling build -t sdist --hooks-only make -C doc locale git commit -a -m "Update doc translation catalogs" make -C doc man git commit -a -m "Update man pages" - name: Build application translations catalogs run: | rm -f po/linkchecker.pot make -C po git commit -a -m "Update application translation catalogs" - name: Push changes run: > git push --set-upstream local man-updates linkchecker-10.5.0/.github/workflows/build.yml000066400000000000000000000131131466565367000213170ustar00rootroot00000000000000# NB: this name is used in the status badge, where we want to see "build: passing" name: build permissions: contents: read on: push: branches: - master pull_request: branches: - master workflow_dispatch: # allow manual triggering from GitHub UI schedule: - cron: "0 5 * * 6" # 5:00 UTC every Saturday jobs: build: name: Python ${{ matrix.python-version }} runs-on: ubuntu-latest strategy: matrix: python-version: - "3.10" - "3.11" - "3.12" - "3.13" toxenv: [py] include: - python-version: "3.9" toxenv: minreqs services: httpbin: image: kennethreitz/httpbin ports: - 8080:80 steps: - name: Install OS dependencies run: | sudo apt-get update sudo apt-get install -y clamav-daemon geoip-database libgeoip-dev gettext - name: Make ClamAV cache directory writeable for cache action run: | sudo chown -R runner:docker /var/lib/clamav - name: ClamAV cache id: cache-clamav uses: actions/cache@v4 with: path: /var/lib/clamav key: clamav-v1 - name: Restore ClamAV directory ownership run: | sudo chown -R clamav:clamav /var/lib/clamav - name: Restart ClamAV Daemon if: ${{ steps.cache-clamav.outputs.cache-hit == 'true' }} run: | sudo service clamav-daemon restart - name: Download the ClamAV signature database if: ${{ steps.cache-clamav.outputs.cache-hit != 'true' }} run: | sudo service clamav-freshclam stop sudo freshclam sudo service clamav-daemon restart sudo service clamav-daemon status - name: Git clone uses: actions/checkout@v4 with: show-progress: false - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: "${{ matrix.python-version }}" allow-prereleases: true - name: Pip cache uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('tox.ini', 'pyproject.toml') }} restore-keys: | ${{ runner.os }}-pip-${{ matrix.python-version }}- ${{ runner.os }}-pip- - name: Install Python dependencies # coverage is required by coverallsapp/github-action run: | python -m pip install -U pip python -m pip install -U hatchling hatch-vcs polib python -m pip install -U tox coverage - name: Wait for ClamAV to be ready run: | while ! test -S /run/clamav/clamd.ctl; do printf "."; sleep 1; done - name: Run tests run: | python -m hatchling build -t sdist --hooks-only python -m tox -e ${{ matrix.toxenv }}-geoip - name: Report to coveralls uses: coverallsapp/github-action@f350da2c033043742f89e8c0b7b5145a1616da6d # v2.1.2 with: parallel: true flag-name: run-${{ matrix.python-version }} finish: needs: build runs-on: ubuntu-latest steps: - name: Close coveralls parallel build uses: coverallsapp/github-action@f350da2c033043742f89e8c0b7b5145a1616da6d # v2.1.2 with: parallel-finished: true docs: # there's some overlap with publish-pages.yml, but this one runs on pull # requests, doesn't publish, and runs more doc checks name: docs runs-on: ubuntu-latest steps: - name: Git clone uses: actions/checkout@v4 with: show-progress: false - name: Install Ubuntu packages run: | sudo apt-get install -y graphviz mandoc - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.x" - name: Pip cache uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-docs-${{ hashFiles('tox.ini') }} restore-keys: | ${{ runner.os }}-pip-docs- ${{ runner.os }}-pip- - name: Install Python packages run: | pip install -U dnspython beautifulsoup4 requests \ hatchling hatch-vcs sphinx sphinx-epytext \ sphinx-intl sphinx-rtd-theme sphinx-sitemap - name: Build run: | python3 -m hatchling build -t sdist --hooks-only make -C doc html make -C doc locale make -C doc man make -C doc check lint: name: ${{ matrix.toxenv }} runs-on: ubuntu-latest strategy: matrix: toxenv: - flake8 - check-python-versions - pylint - yamllint steps: - name: Git clone uses: actions/checkout@v4 with: show-progress: false - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.x" - name: Pip cache uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.toxenv }}-${{ hashFiles('tox.ini') }} restore-keys: | ${{ runner.os }}-pip-${{ matrix.toxenv }}- ${{ runner.os }}-pip- - name: Install dependencies run: | python -m pip install -U pip python -m pip install -U hatchling hatch-vcs polib python -m pip install -U tox - name: Run ${{ matrix.toxenv }} run: python -m tox -e ${{ matrix.toxenv }} linkchecker-10.5.0/.github/workflows/publish-docker.yml000066400000000000000000000036631466565367000231440ustar00rootroot00000000000000# https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions#publishing-a-package-using-an-action name: Create and publish a Docker image on: push: branches: ['master'] tags: 'v*' workflow_dispatch: env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: build-and-push-image: runs-on: ubuntu-latest permissions: attestations: write contents: read id-token: write packages: write steps: - name: Log in to the Container registry uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.10 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} flavor: latest=true tags: | type=semver,pattern={{version}} type=ref,event=branch - name: Build and push Docker image id: push uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 with: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - name: Attest uses: actions/attest-build-provenance@v1 with: subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} subject-digest: ${{ steps.push.outputs.digest }} push-to-registry: false - name: Delete oldest Docker images uses: actions/delete-package-versions@v5 with: package-name: 'linkchecker' package-type: 'container' min-versions-to-keep: 20 delete-only-untagged-versions: 'true' linkchecker-10.5.0/.github/workflows/publish-pages.yml000066400000000000000000000030731466565367000227670ustar00rootroot00000000000000name: Publish LinkChecker Documentation on GitHub Pages on: push: branches: ["master"] release: types: [released] jobs: run: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v4 with: # Needed for hatch-vcs to extract LinkChecker version from tag # https://github.com/actions/checkout/issues/249 fetch-depth: 0 show-progress: false - name: Install Ubuntu packages run: sudo apt install graphviz # Ensure sphinx-autogen is installed in PATH - name: Setup Python uses: actions/setup-python@v5 with: python-version: "3.x" - name: Install Python packages run: | pip install dnspython beautifulsoup4 requests \ hatchling hatch-vcs # Allow sphinx-rtd-theme to choose the versions of sphinx & docutils pip install sphinx-rtd-theme pip install sphinx-epytext sphinx-sitemap - name: Build run: | python3 -m hatchling build -t sdist --hooks-only make -C doc html - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: "doc/html" deploy: needs: run runs-on: ubuntu-latest permissions: pages: write id-token: write environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 linkchecker-10.5.0/.github/workflows/release-files.yml000066400000000000000000000031451466565367000227440ustar00rootroot00000000000000name: Create distribution files for a new release on: release: types: [released] jobs: run: runs-on: ubuntu-latest permissions: attestations: write contents: write id-token: write steps: - uses: actions/checkout@v4 with: # Needed for hatch-vcs to extract LinkChecker version from tag # https://github.com/actions/checkout/issues/249 fetch-depth: 0 show-progress: false - name: Install Ubuntu packages run: sudo apt install git - name: Setup Python uses: actions/setup-python@v5 with: python-version: "3.x" - name: Install Python packages run: > pip3 install -U hatchling hatch-vcs polib twine - name: Set SOURCE_DATE_EPOCH run: > echo "SOURCE_DATE_EPOCH=$(git log -n 1 ${{ github.sha }} --format=%ct)" >> $GITHUB_ENV - name: Create distribution files run: > python3 -m hatchling build - name: Attest uses: actions/attest-build-provenance@v1 with: subject-path: 'dist/*.tar.gz, dist/*.whl' - name: Check distribution files run: > twine check dist/*.{tar.gz,whl} - name: Calculate checksums for distribution files run: > sha256sum dist/*.{tar.gz,whl} - name: Add files to release run: > gh release upload ${{ github.ref_name }} dist/* env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - name: Publish distribution files to PyPI uses: pypa/gh-action-pypi-publish@release/v1 linkchecker-10.5.0/.project000066400000000000000000000005551466565367000155550ustar00rootroot00000000000000 linkchecker org.python.pydev.PyDevBuilder org.python.pydev.pythonNature linkchecker-10.5.0/.pydevproject000066400000000000000000000006451466565367000166250ustar00rootroot00000000000000 Default python 2.7 /linkchecker-git linkchecker-10.5.0/.pylintrc000066400000000000000000000001421466565367000157430ustar00rootroot00000000000000[TYPECHECK] ignored-modules=meliae, win32com.client, yappi [VARIABLES] additional-builtins=_, _n linkchecker-10.5.0/.yamllint000066400000000000000000000001501466565367000157270ustar00rootroot00000000000000extends: default rules: document-start: disable line-length: disable truthy: {check-keys: false} linkchecker-10.5.0/CODE_OF_CONDUCT.rst000066400000000000000000000102421466565367000171070ustar00rootroot00000000000000Contributor Covenant Code of Conduct ==================================== Our Pledge ---------- In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. Our Standards ------------- Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences - Gracefully accepting constructive criticism - Focusing on what is best for the community - Showing empathy towards other community members Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment - Publishing others’ private information, such as a physical or electronic address, without explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting Our Responsibilities -------------------- Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. Scope ----- This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. Enforcement ----------- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting one of the persons listed below. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project maintainers is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership. Project maintainers are encouraged to follow the spirit of the `Django Code of Conduct Enforcement Manual `__ when receiving reports. Contacts -------- The following people have volunteered to be available to respond to Code of Conduct reports. They have reviewed existing literature and agree to follow the aforementioned process in good faith. They also accept OpenPGP-encrypted email: - Antoine Beaupré anarcat@debian.org Attribution ----------- This Code of Conduct is adapted from the `Contributor Covenant `__, version 1.4, available at `http://contributor-covenant.org/version/1/4 `__ Changes ------- The Code of Conduct was modified to refer to *project maintainers* instead of *project team* and small paragraph was added to refer to the Django enforcement manual. Note: We have so far determined that writing an explicit enforcement policy is not necessary, considering the available literature already available online and the relatively small size of the community. This may change in the future if the community grows larger. linkchecker-10.5.0/CONTRIBUTING.rst000066400000000000000000000134131466565367000165440ustar00rootroot00000000000000Contribution Guide ================== This document outlines how to contribute to this project. It details instructions on how to submit issues, bug reports and patches. Before you participate in the community, you should also agree to respect the code of conduct, shipped in :doc:`CODE_OF_CONDUCT.rst ` in the source code. Positive feedback ----------------- Even if you have no changes, suggestions, documentation or bug reports to submit, even just positive feedback like “it works” goes a long way. It shows the project is being used and gives instant gratification to contributors. So we welcome emails that tell us of your positive experiences with the project or just thank you notes. Contact maintainers directly or submit a closed issue with your story. You can also send your “thanks” through https://saythanks.io/. Issues and bug reports ---------------------- We want you to report issues you find in the software. It is a recognized and important part of contributing to this project. All issues will be read and replied to politely and professionally. Issues and bug reports should be filed on the `issue tracker `__. Issue triage ^^^^^^^^^^^^ Issue triage is a useful contribution as well. You can review the `issues `__ in the `project page `__ and, for each issue: - try to reproduce the issue, if it is not reproducible, label it with ``help-wanted`` and explain the steps taken to reproduce - if information is missing, label it with ``invalid`` and request specific information - if the feature request is not within the scope of the project or should be refused for other reasons, use the ``wontfix`` label and close the issue - mark feature requests with the ``enhancement`` label, bugs with ``bug``, duplicates with ``duplicate`` and so on… Note that some of those operations are available only to project maintainers, see below for the different statuses. Security issues ^^^^^^^^^^^^^^^ Security issues should first be disclosed privately to the project maintainers, which support receiving encrypted emails through the usual OpenPGP key discovery mechanisms. This project cannot currently afford bounties for security issues. We would still ask that you coordinate disclosure, giving the project a reasonable delay to produce a fix and prepare a release before public disclosure. Public recognition will be given to reporters security issues if desired. We otherwise agree with the `Disclosure Guidelines `__ of the `HackerOne project `__, at the time of writing. Patches ------- Patches can be submitted through `pull requests `__ on the `project page `__. Some guidelines for patches: - A patch should be a minimal and accurate answer to exactly one identified and agreed problem. - A patch must compile cleanly and pass project self-tests on all target platforms. - A patch commit message must consist of a single short (less than 50 characters) line stating a summary of the change, followed by a blank line and then a description of the problem being solved and its solution, or a reason for the change. Write more information, not less, in the commit log. - Patches should be reviewed by at least one maintainer before being merged. Project maintainers should merge their own patches only when they have been approved by other maintainers, unless there is no response within a reasonable timeframe (roughly one week) or there is an urgent change to be done (e.g. security or data loss issue). As an exception to this rule, this specific document cannot be changed without the consensus of all administrators of the project. Note: Those guidelines were inspired by the `Collective Code Construction Contract `__. The document was found to be a little too complex and hard to read and wasn’t adopted in its entirety. See this `discussion `__ for more information. Patch triage ^^^^^^^^^^^^ You can also review existing pull requests, by cloning the contributor’s repository and testing it. If the tests do not pass (either locally or in Travis), if the patch is incomplete or otherwise does not respect the above guidelines, submit a review with “changes requested” with reasoning. Membership ---------- There are three levels of membership in the project, Administrator (also known as “Owner” in GitHub), Maintainer (also known as “Member”), or regular users (everyone with or without a GitHub account). Anyone is welcome to contribute to the project within the guidelines outlined in this document, regardless of their status, and that includes regular users. Maintainers can: - do everything regular users can - review, push and merge pull requests - edit and close issues Administrators can: - do everything maintainers can - add new maintainers - promote maintainers to administrators Regular users can be promoted to maintainers if they contribute to the project, either by participating in issues, documentation or pull requests. Maintainers can be promoted to administrators when they have given significant contributions for a sustained timeframe, by consensus of the current administrators. This process should be open and decided as any other issue. Maintainers can be demoted by administrators and administrators can be demoted by the other administrators’ consensus. Unresponsive maintainers or administrators can be removed after a month unless they specifically announced a leave. linkchecker-10.5.0/COPYING000066400000000000000000000431031466565367000151350ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 of the License, or (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. linkchecker-10.5.0/Dockerfile000066400000000000000000000013601466565367000160730ustar00rootroot00000000000000# Use the maximum Python version tested FROM python:3.12-slim # linkchecker creates $XDG_CONFIG_HOME/linkchecker/ (700) containing linkcheckerrc et al ENV HOME /tmp # Enables access to local files when run with -v "$PWD":/mnt VOLUME /mnt WORKDIR /mnt # Dependencies change on their own schedule so install them separately RUN pip install --no-cache-dir beautifulsoup4 dnspython requests polib RUN set -x \ && apt-get update -qq \ && apt-get install -y -qq --no-install-recommends git \ && pip install --no-cache-dir git+https://github.com/linkchecker/linkchecker.git \ && apt-get -y -qq purge git \ && apt-get autoremove -y -qq \ && apt-get clean -y -qq all \ && rm -rf /var/lib/apt/lists/* ENTRYPOINT ["linkchecker"] linkchecker-10.5.0/Makefile000066400000000000000000000014111466565367000155360ustar00rootroot00000000000000# This Makefile is only used by developers. PAGER ?= less all: @echo "Read the file doc/install.txt to see how to build and install this package." clean: git clean -fdx locale: $(MAKE) -C po linkcheck/_release.py: hatchling build -t sdist --hooks-only test: linkcheck/_release.py tox -e py upload: twine upload dist/LinkChecker* homepage: linkcheck/_release.py make -C doc html dist: hatchling build check: flake8 yamllint .github make -C doc check make -C po check releasecheck: check @if egrep -i "xx\.|xxxx|\.xx|^[[:digit:]]+\.x" doc/changelog.txt > /dev/null; then \ echo "Could not release: edit doc/changelog.txt release date"; false; \ fi count: @sloccount linkcheck tests .PHONY: test count upload all clean .PHONY: locale dist homepage linkchecker-10.5.0/README.rst000066400000000000000000000045411466565367000155740ustar00rootroot00000000000000LinkChecker ============ |Build Status|_ |License|_ .. |Build Status| image:: https://github.com/linkchecker/linkchecker/actions/workflows/build.yml/badge.svg?branch=master .. _Build Status: https://github.com/linkchecker/linkchecker/actions/workflows/build.yml .. |License| image:: https://img.shields.io/badge/license-GPL2-d49a6a.svg .. _License: https://opensource.org/licenses/GPL-2.0 Check for broken links in web sites. Features --------- - recursive and multithreaded checking and site crawling - output in colored or normal text, HTML, SQL, CSV, XML or a sitemap graph in different formats - HTTP/1.1, HTTPS, FTP, mailto: and local file links support - restrict link checking with regular expression filters for URLs - proxy support - username/password authorization for HTTP and FTP - honors robots.txt exclusion protocol - Cookie support - HTML5 support - a command line and web interface - various check plugins available Installation ------------- Python 3.9 or later is needed. Using pip to install LinkChecker: ``pip3 install linkchecker`` pipx can also be used to install LinkChecker. The version in the pip repository may be old, to find out how to get the latest code, plus platform-specific information and other advice see `doc/install.txt`_ in the source code archive. .. _doc/install.txt: https://linkchecker.github.io/linkchecker/install.html Usage ------ Execute ``linkchecker https://www.example.com``. For other options see ``linkchecker --help``, and for more information the manual pages `linkchecker(1)`_ and `linkcheckerrc(5)`_. .. _linkchecker(1): https://linkchecker.github.io/linkchecker/man/linkchecker.html .. _linkcheckerrc(5): https://linkchecker.github.io/linkchecker/man/linkcheckerrc.html Docker usage ------------- If you do not want to install any additional libraries/dependencies you can use the Docker image which is published on GitHub Packages. Example for external web site check:: docker run --rm -it -u $(id -u):$(id -g) ghcr.io/linkchecker/linkchecker:latest --verbose https://www.example.com Local HTML file check:: docker run --rm -it -u $(id -u):$(id -g) -v "$PWD":/mnt ghcr.io/linkchecker/linkchecker:latest --verbose index.html In addition to the rolling latest image, uniquely tagged images can also be found on the `packages`_ page. .. _packages: https://github.com/linkchecker/linkchecker/pkgs/container/linkchecker linkchecker-10.5.0/cgi-bin/000077500000000000000000000000001466565367000154115ustar00rootroot00000000000000linkchecker-10.5.0/cgi-bin/README000066400000000000000000000002631466565367000162720ustar00rootroot00000000000000For the HTML files in the lconline directory to work, your web server must have mod_negotiation enabled. Or you can just remove the .XY suffixes from the language-specific files. linkchecker-10.5.0/cgi-bin/lc.wsgi000066400000000000000000000014471466565367000167100ustar00rootroot00000000000000#!/usr/bin/python3 # Copyright (C) 2012 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. from linkcheck.lc_cgi import application linkchecker-10.5.0/cgi-bin/lconline/000077500000000000000000000000001466565367000172145ustar00rootroot00000000000000linkchecker-10.5.0/cgi-bin/lconline/check.js000066400000000000000000000011221466565367000206230ustar00rootroot00000000000000// check url validity function isValid (thisForm) { if (thisForm.url.value=="" || thisForm.url.value=="http://") { alert(gettext("Empty URL was given.")); thisForm.url.select(); thisForm.url.focus(); return false; } if (!checkSyntax(thisForm.url.value)) { alert(gettext("Invalid URL was given.")); thisForm.url.select(); thisForm.url.focus(); return false; } return true; } // check url syntax function checkSyntax (url) { var syntax = /^https?:\/\/[-_a-zA-Z0-9.\/=%?~]+$/; return syntax.test(url); } linkchecker-10.5.0/cgi-bin/lconline/favicon.ico000066400000000000000000000070661466565367000213460ustar00rootroot00000000000000h& ( @o$ñmF#v`r߻YˏU='r0šb0_?۬}ESk9nM$w]ư=mAa'T9!UrO#̡OӰy,N]t;yL̷cӄ:ʆfb4͜bg;ⵋ؞rydOFyS4mA^R. _Kl$gz†N9Fund8Z6t[F{Q־xw)\Do5g-ҶkʸOc@pn-乕z:Iw9ӦwÎ\Iu#l,ck*d@_,j.M۾T,}<Y2 \<ŠΧuU:äu3V!T濔^9fOb0vGp*Gò\>"]҉9c<F X;Ҹfd,v]azKտвԶe-[=wIva£\<6A[8-av1b yFg*B?u)DkX$Lc]\(#H`.'~xY{piUoC 3se4OQ@}0TnZ_EI&^ dNP9?( @҄/m;ᶞ~fRUyUnKiL2rE&_*ТwÌVμj~IoL }_WߝTd*ݰW6Ɲt~O S }\:nIn=ͼ\op0iҎBɨf ƍ|<ʪ1ΙbֻdB_2q•u\D٦nSHk;^ʲNxEW2fx!pɀY@Z<sCױoyTx+¯` ȁ;qM'c#fAla!`’dḎϒTh=Ve/\Ξ|V.r>ߢ_U*aV"թүvj&ً7Lw\EշnS֦xOGWОj`jvU5暑[ |Xß}]ĨWӷ̠u3/{FX< i?ِ@gd7 W2 ŶpEkg,yO, Dzj2hȇ@b@(`2]:Gޓii|cJ˘X%c2ȵƩo?™p_D ֠gǢoRuCdw>K)kP7]ײía:zW ~(ܙN[ro'Pac:rYnH!m>\Tш7vJ`D式kOez ^<aӿnM,jސ:id?ǡ[և0tA j,w)șhyP(]U-`+ͧrJɐYֵթΰ٫|Sлq7lWL`jjA="%[AgE%\\\%cT L J 'GJ+lݜezk㺨uS@@DzXX9I9vq@@tߗDM&mMm>@&& !Pd1ۛ㗸~pT.|ӂaizbNU ̒5̗AsW033.4Zd fVs(R;7,;FQvsbFƋ,hы.q@aT{s(HrЉn8.T*vT{bHxY n)H0q9(bFKx)/O BorH9vbǐ?oyOO)U3NfvF?/OC8h,`|f#R*/OرCO/4wʾX5H,/n4CC nZc$X2}ZBזOnקwNQ@^BBC4ZZ3d6:;BB44_|dBC-_]dshħZn`b`^^u;3<<>FTF???linkchecker-10.5.0/cgi-bin/lconline/index.html000066400000000000000000000007721466565367000212170ustar00rootroot00000000000000 LinkChecker Online Please use a frame capable browser. linkchecker-10.5.0/cgi-bin/lconline/lc.css000066400000000000000000000003601466565367000203230ustar00rootroot00000000000000h2 { font-family: Verdana,sans-serif; font-size: 22pt; font-weight: bold } body { font-family: Arial,sans-serif; font-size: 11pt } td { font-family:Arial,sans-serif; font-size:11pt } code { font-family: Courier } a:hover { color: #34a4ef } linkchecker-10.5.0/cgi-bin/lconline/lc_cgi.html.de000066400000000000000000000035171466565367000217170ustar00rootroot00000000000000 LinkChecker Online

LinkChecker Online

(läuft mit Öl vom LinkChecker)
Url:
Optionen: Rekursionstiefe: Prüfe Anker in HTML:
Nur Warnungen und Fehler ausgeben: Ausgabe:
linkchecker-10.5.0/cgi-bin/lconline/lc_cgi.html.en000066400000000000000000000032331466565367000217240ustar00rootroot00000000000000 LinkChecker Online

LinkChecker Online

(powered by LinkChecker)
Url:
Options: Recursion Level: Check anchors in HTML:
Log only warnings and errors: Output language:
linkchecker-10.5.0/cgi-bin/lconline/leer.html.de000066400000000000000000000006051466565367000214210ustar00rootroot00000000000000 Leer
Keine Links geprüft!
linkchecker-10.5.0/cgi-bin/lconline/leer.html.en000066400000000000000000000006101466565367000214270ustar00rootroot00000000000000 Empty
No links checked, dude!
linkchecker-10.5.0/config/000077500000000000000000000000001466565367000153465ustar00rootroot00000000000000linkchecker-10.5.0/config/create.sql000066400000000000000000000012011466565367000173240ustar00rootroot00000000000000-- tested with postgresql -- you can add a unique sequence id to the table if you want drop table linksdb; create table linksdb ( urlname varchar(256) not null, parentname varchar(256), baseref varchar(256), valid int, result varchar(256), warning varchar(512), info varchar(512), url varchar(256), line int, col int, name varchar(256), checktime int, dltime int, size int, cached int, level int not null, modified varchar(256) ); linkchecker-10.5.0/config/linkchecker-completion000066400000000000000000000007621466565367000217270ustar00rootroot00000000000000# Install this file into directory /etc/bash_completion.d/ on a # Debian Linux system. For other system read the documentation that # comes with the bash-completion package. have linkchecker && _linkcheck() { local cur prev COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} if type _argcomplete &> /dev/null; then _argcomplete "$@" else _filedir fi return 0 } [ "$have" ] && complete $filenames -F _linkcheck linkchecker linkchecker-10.5.0/config/linkchecker.apache2.conf000066400000000000000000000020611466565367000220000ustar00rootroot00000000000000 WSGIScriptAlias /lconlinewsgi/lc.wsgi /usr/lib/cgi-bin/lc.wsgi Alias /lconline /usr/share/linkchecker/lconline # allow people to read the files Options Indexes MultiViews = 2.3> Require local Order deny,allow Deny from all Allow from 127.0.0.0/255.0.0.0 # Before uncommenting the following lines please put IP address # of your computer in the Allow line # Allow from REPLACE-WITH.YOUR-HOST.IP-ADDRESS # IPv6 addresses work only with apache2 Allow from ::1/128 = 2.3> Require local Order deny,allow Deny from all Allow from 127.0.0.0/255.0.0.0 # Before uncommenting the following lines please put IP address # of your computer in the Allow line # Allow from REPLACE-WITH.YOUR-HOST.IP-ADDRESS # IPv6 addresses work only with apache2 Allow from ::1/128 linkchecker-10.5.0/doc/000077500000000000000000000000001466565367000146465ustar00rootroot00000000000000linkchecker-10.5.0/doc/Makefile000066400000000000000000000011301466565367000163010ustar00rootroot00000000000000MANFILES:=linkchecker.1 linkcheckerrc.5 LOCALES:=en de all: html man html: clean make -C src html locale: make -C src locale man: make -C src man; \ make -C src -e SPHINXOPTS="-D language='de' -t de" LANGUAGE="de" man # check all man files for formatting warnings check: @for loc in $(LOCALES); do \ for manfile in $(MANFILES); do \ echo "Checking man/$$loc/$$manfile"; \ LC_ALL=en_US.UTF-8 MANWIDTH=80 mandoc -T lint -W error man/$$loc/$$manfile; \ done; \ done clean: rm -rf src/_build; \ rm -rf src/code/linkcheck; \ rm -rf html .PHONY: check clean html locale man linkchecker-10.5.0/doc/changelog.txt000066400000000000000000003446331466565367000173530ustar00rootroot0000000000000010.5.0 (released 03.09.2024) Features: - ignorewarningsforurls setting to match URLs and warnings to ignore Fixes - Documentation updates 10.4.0 (released 11.12.2023) Features: - FIFOs can be used with --config and --cookiefile Changes: - Minimum Python version required is 3.9 - ms-windows-store added to the list of ignored schemes - linkchecker will exit if problems with a configuration file or cookie file are detected on startup Fixes - A cookie file that could not be parsed was causing an exception - Documentation updates 10.3.0 (released 18.09.2023) Features: - TextLogger message wrapping is configurable using wraplength Changes: - Minimum Python version required is 3.8 - HTTP redirect causes a warning, http-redirected - Ignored warning messages are logged as information - Installing from git archives is re-enabled - Support for checking NNTP and Telnet links is removed Fixes - -p/--password was being ignored - FTP checker was raising a TypeError - FTP checker was ignoring maxfilesizedownload - Documentation updates 10.2.1 (released 05.12.2022) Fixes - Minimum Beautiful Soup version required restored to 4.8.1 - Documentation updates 10.2.0 (released 21.11.2022) Features: - ignoreerrors setting to disregard errors for URLs after checking - AnchorCheck plugin has partial support for checking local files Changes: - Minimum Python version required is 3.7 - PyXDG is no longer used - setuptools and setup.py replaced with hatchling and pyproject.toml - The application version is derived from git tags using hatch-vcs - Binary translation catalogs are produced using polib during distribution package building and are now included in sdist packages - gemini, tg (Telegram) and whatsapp added to the list of ignored schemes - Warning url-rate-limited renamed to http-rate-limited - maxrequestspersecond can be less than 1 - maxrequestspersecond greater than 10 is used unchanged if the HTTP server returns a LinkChecker response header - When a sitemap is discovered from a robots.txt file, the robots.txt is logged as the sitemap parent URL Fixes: - Checking directories containing Unicode filenames - Parsing srcset attributes with multiple image candidates - resultcachesize setting was being ignored - sitemap output when using multiple threads - AnchorCheck plugin is re-enabled - Multiple man page and other documentation updates 10.1.0 (released 22.12.2021) Features: - resultcachesize setting to specify the maximum size of the result cache - quiet/-q also sets the application logging level to warning - preconnect link types are checked using DNS - Dutch (nl_NL) application translation Changes: - The application version is derived from git tags using setuptools_scm - The AnchorCheck plugin is disabled - Binary translation catalogs are not included with the source; if present, polib is used by setup.py to compile translations - The ftp_proxy environment variable is not supported. GNOME and KDE proxy settings are not read - If Requests returns a character encoding of ISO-8859-1, Beautiful Soup is used to determine the encoding of a page; robots.txt are assumed to be UTF-8 - The linkchecker command is generated using an entry point - GitHub Actions has replaced Travis Fixes: - An HTTP server can be used as an HTTPS proxy - Multiple man page and other documentation updates 10.0.1 (released 29.1.2021) Changes: - Minimum supported version of Beautiful Soup is 4.8.1 Fixes: - wsgi: Fix failure due to status logging being enabled 10.0 (released 15.1.2021) Features: - Uses Python 3 - C extension modules have been replaced, now uses Beautiful Soup - Documentation converted to reStructuredText and generated with Sphinx Changes: - cmdline: Remove options replaced by plugins and made ineffective in 9.0 - configuration: Update proxy settings support for GNOME 3 and KDE 5 - configuration: login entries must now match the case of form element names - logging: blacklist has been renamed to failures - checking: Handle HTTP status code 429: Too Many Requests with a new warning: WARN_URL_RATE_LIMITED, instead of an error - checking: Use timeout when fetching login forms and robots.txt - checking: login forms with only one field are supported - checking: slack added to the list of ignored schemes - tests: Test coverage has been increased - biplist is no longer used because plistlib now supports binary files - dnspython and miniboa are no longer included - Custom MANIFEST check replaced with check-manifest - Code now passes flake8 checks Fixes: - configuration: status=0 is no longer ignored - logging: Fix CSV logger not recognising base part setting - logging: Fix CSV output containing increasing number of null byte characters. - checking: Fix treating data: URIs in srcset values as links - checking: Fix critical exception if srcset value ends with a comma - checking: Fix critical exception when parsing a URL with a ] - plugins: The AnchorCheck plugin is working again - plugins: The W3C validation API has changed, CssSyntaxCheck has been updated, HtmlSyntaxCheck plugin is disabled - doc: Multiple man page and other documentation updates 9.4 "just passing by" (released 12.4.2018) Features: - checking: Support itms-services: URLs. Closes: GH bug #532 - checking: Support XDG Base Directory Specification for configuration and data. Closes: GH bug #44 - add Dockerfile - use xdg dirs for config & data - use tox for tests and fix travis build - add --no-robots commandline flag - Added plugin for parsing and checking links in Markdown files Changes: - installation: Remove dependency on msgfmt.py by pre-generating the *.mo files and adding them to version control. Reason was the difficulty to run msgfmt.py under both Python 2 and 3. - checking: When checking SSL certificates under POSIX systems try to use the system certificate store. - logging: improved debugging by also enabling urllib3 output - remove third-party packages and use them as dependency - Allow wayback-format urls without affecting atom 'feed' urls - Move dev requirements into dev-requirements.txt - Crawl HTML attributes in deterministic order - Remove platform-specific installer stuff and ensure a build .whl wheel file can be built. - Move GUI files to separate project Fixes: - checking: Correct typos in the proxy handling code. Closes: GH bug #536 - checking: Add to default HTTP client headers instead of replacing. - cmdline: Reactivate paging of help pages. - requirements: Fix requests module version check. Closes: GH bug #548 - load cookies from the --cookiefile correctly - fix incorrect call to the logging module - Fix TypeError: hasattr(): attribute name must be string - fix HTTPS URL checks 9.3 "Better Living Through Chemistry" (released 16.7.2014) Features: - checking: Parse and check links in PDF files. - checking: Parse Refresh: and Content-Location: HTTP headers for URLs. Changes: - plugins: PDF and Word checks are now parser plugins (PdfParser, WordParser). Both plugins are not enabled by default since they require third party modules. - plugins: Print a warning for enabled plugins that could not import needed third party modules. - checking: Treat empty URLs as same as parent URL. Closes: GH bug #524 - installation: Replaced the twill dependency with local code. Fixes: - checking: Catch XML parse errors in sitemap XML files and print them as warnings. Patch by Mark-Hetherington. Closes: GH bug #516 - checking: Fix internal URL match pattern. Patch by Mark-Hetherington. Closes: GH bug #510 - checking: Recalculate extern status after HTTP redirection. Patch by Mark-Hetherington. Closes: GH bug #515 - checking: Do not strip quotes from already resolved URLs. Closes: GH bug #521 - cgi: Sanitize configuration. Closes: GH bug #519 - checking: Use user-supplied authentication and proxies when requestiong robot.txt. - plugins: Fix Word file check plugin. Closes: GH bug #530 9.2 "Rick and Morty" (released 23.4.2014) Fixes: - checking: Don't scan external robots.txt sitemap URLs. Closes: GH bug #495 - installation: Correct case for pip install command. Closes: GH bug #498 Features: - checking: Parse and check HTTP Link: headers. - checking: Support parsing of HTML image srcset attributes. - checking: Support parsing of HTML schema itemtype attributes. 9.1 "Don Jon" (released 30.3.2014) Features: - checking: Support parsing of sitemap and sitemap index XML files. Closes: GH bug #413 - checking: Add new HTTP header info plugin. - logging: Support arbitrary encodings in CSV output. Closes: GH bug #467 - installation: Use .gz compression for source release to support "pip install". Closes: GH bug #461 Changes: - checking: Ignored URLs are reported earlier now. - checking: Updated the list of unkonwn or ignored URI schemes. - checking: Internal errors do not disable check threads anymore. - checking: Disable URL length warning for data: URLs. - checking: Do not warn about missing addresses on mailto links that have subjects. - checking: Check and display SSL certificate info even on redirects. Closes: GH bug #489 - installation: Check requirement for Python requests >= 2.2.0. Closes: GH bug #478 - logging: Display downloaded bytes. Fixes: - checking: Fix internal errors in debug output. Closes: GH bug #472 - checking: Fix URL result caching. - checking: Fix assertion in external link checking. - checking: Fix SSL errors on Windows. Closes: GH bug #471 - checking: Fix error when SNI checks are enabled. Closes: GH bug #488 - gui: Fix warning regex settings. Closes: GH bug #485 9.0 "The Wolf of Wall Street" (released 3.3.2014) Features: - checking: Support connection and content check plugins. - checking: Move lots of custom checks like Antivirus and syntax checks into plugins (see upgrading.txt for more info). - checking: Add options to limit the number of requests per second, allowed URL schemes and maximum file or download size. Closes: GH bug #397, #465, #420 - checking: Support checking Sitemap: URLs in robots.txt files. - checking: Reduced memory usage when caching checked links. Closes: GH bug #429 - gui: UI language can be changed dynamically. Closes: GH bug #391 Changes: - checking: Use the Python requests module for HTTP and HTTPS requests. Closes: GH bug #393, #463, #417 - logging: Removed download, domains and robots.txt statistics. - logging: HTML output is now in HTML5. - checking: Removed 301 warning since 301 redirects are used a lot without updating the old URL links. Also, recursive redirection is not checked any more since there is a maximum redirection limit anyway. Closes: GH bug #444, #419 - checking: Disallowed access by robots.txt is an info now, not a warning. Otherwise it produces a lot of warnings which is counter-productive. - checking: Do not check SMTP connections for mailto: URLs anymore. It resulted in lots of false warnings since spam prevention usually disallows direct SMTP connections from unrecognized client IPs. - checking: Only internal URLs are checked as default. To check external urls use --check-extern. Closes: GH bug #394, #460 - checking: Document that gconf and KDE proxy settings are parsed. Closes: GH bug #424 - checking: Disable twill page refreshing. Closes: GH bug #423 - checking: The default number of checking threads is 10 now instead of 100. Fixes: - logging: Status was printed every second regardless of the configured wait time. - logging: Add missing column name to SQL insert command. Closes: GH bug #399 - checking: Several speed and memory usage improvements. - logging: Fix --no-warnings option. Closes: GH bug #457 - logging: The -o none now sets the exit code. Closes: GH bug #451 - checking: For login pages, use twill form field counter if the field has neither name nor id. Closes: GH bug #428 - configuration: Check regular expressions for errors. Closes: GH bug #410 8.6 "About Time" (released 8.1.2014) Changes: - checking: Add "Accept" HTTP header. Closes: GH bug #395 Fixes: - installer: Include missing logger classes for Windows and OSX installer. Closes: GH bug #448 8.5 "Christmas Vacation" (released 24.12.2013) Features: - checking: Make per-host connection limits configurable. - checking: Avoid DoS in SSL certificate host matcher. Changes: - checking: Always use the W3C validator to check HTML or CSS syntax. - checking: Remove the http-wrong-redirect warning. - checking: Remove the url-content-duplicate warning. - checking: Make SSL certificate verification optional and allow user-specified certificate files. Closes: GH bug #387 - cmdline: Replace argument parsing. No changes in functionality, only the help text will be formatted different. - gui: Check early if help files are not found. Closes: GH bug #437 - gui: Remember the last "Save result as" selection. Closes: GH bug #380 Fixes: - checking: Apache Coyote (the HTTP server of Tomcat) sends the wrong Content-Type on HEAD requests. Automatically fallback to GET in this case. Closes: GH bug #414 - checking: Do not use GET on POST forms. Closes: GH bug #405 - scripts: Fix argument parsing in linkchecker-nagios Closes: GH bug #404 - installation: Fix building on OS X systems. 8.4 "Frankenweenie" (released 25.01.2013) Features: - checking: Support URLs. - logging: Sending SIGUSR1 signal prints the stack trace of all current running threads. This makes debugging deadlocks easier. - gui: Support Drag-and-Drop of local files. If the local file is a LinkChecker project (.lcp) file it is loaded, else the check URL is set to the local file URL. Changes: - checking: Increase per-host connection limits to speed up checking. Fixes: - checking: Fix a crash when closing a Word document after scanning failed. Closes: GH bug #369 - checking: Catch UnicodeError from idna.encode() fixing an internal error when trying to connect to certain invalid hostnames. - checking: Always close HTTP connections without body content. See also http://bugs.python.org/issue16298 Closes: GH bug #376 8.3 "Mahna Mahna Killer" (released 6.1.2013) Features: - project: The Project moved to Github. Closes: GH bug #368 Changes: - logging: Print system arguments (sys.argv) and variable values in internal error information. - installation: Install the dns Python module into linkcheck_dns subdirectory to avoid conflicts with an upstream python-dns installation. Fixes: - gui: Fix storing of ignore lines in options. Closes: SF bug #3587386 8.2 "Belle De Jour" (released 9.11.2012) Changes: - checking: Print a warning when passwords are found in the configuration file and the file is accessible by others. - checking: Add debug statements for unparseable content types. Closes: SF bug #3579714 - checking: Turn off caching. This improves memory performance drastically and it's a very seldom used feature - judging from user feedback over the years and my own experience. - checking: Only allow checking of local files when parent URL does not exist or it's also a file URL. Fixes: - checking: Fix anchor checking of cached HTTP URLs. Closes: SF bug #3577743 - checking: Fix cookie path matching with empty paths. Closes: SF bug #3578005 - checking: Fix handling of non-ASCII exceptions (regression in 8.1). Closes: SF bug #3579766 - configuration: Fix configuration directory creation on Windows systems. Closes: SF bug #3584837 8.1 "Safety Not Guaranteed" (released 14.10.2012) Features: - checking: Allow specification of maximum checking time or maximum number of checked URLs. - checking: Send a HTTP Do-Not-Track header. - checking: Check URL length. Print error on URL longer than 2000 characters, warning for longer than 255 characters. - checking: Warn about duplicate URL contents. - logging: A new XML sitemap logger can be used that implements the protocol defined at http://www.sitemaps.org/protocol.php. Changes: - doc: Mention 7-zip and Peazip to extract the .tar.xz under Windows. Closes: SF bug #3564733 - logging: Print download and cache statistics in text output logger. - logging: Print warning tag in text output logger. Makes warning filtering more easy. - logging: Make the last modification time a separate field in logging output. See doc/upgrading.txt for compatibility changes. - logging: All sitemap loggers log all valid URLs regardless of the --warnings or --complete options. This way the sitemaps can be logged to file without changing the output of URLs in other loggers. - logging: Ignored warnings are now never logged, even when the URL has errors. - checking: Improved robots.txt caching by using finer grained locking. - checking: Limit number of concurrent connections to FTP and HTTP servers. This avoids spurious BadStatusLine errors. Fixes: - logging: Close logger properly on I/O errors. Closes: SF bug #3567476 - checking: Fix wrong method name when printing SSL certificate warnings. - checking: Catch ValueError on invalid cookie expiration dates. Patch from Charles Jones. Closes: SF bug #3575556 - checking: Detect and handle remote filesystem errors when checking local file links. 8.0 "Luminaris" (released 2.9.2012) Features: - checking: Verify SSL certificates for HTTPS connections. Both the hostname and the expiration date are checked. - checking: Always compare encoded anchor names. Closes: SF bug #3538365 - checking: Support WML sites. Closes: SF bug #3553175 - checking: Show number of parsed URLs in page content. - cmdline: Added Nagios plugin script. Changes: - dependencies: Python >= 2.7.2 is now required - gui: Display debug output text with fixed-width font. - gui: Display the real name in the URL properties. Closes: SF bug #3542976 - gui: Make URL properties selectable with the mouse. Closes: SF bug #3561129 - checking: Ignore feed: URLs. - checking: --ignore-url now really ignores the URLs instead of checking only the syntax. - checking: Increase the default number of checker threads from 10 to 100. Fixes: - gui: Fix saving of the debugmemory option. - checking: Do not handle attribute as parent URL but as normal URL to be checked. - checking: Fix UNC path handling on Windows. - checking: Detect more sites not supporting HEAD requests properly. Closes: SF bug #3535981 7.9 "The Dark Knight" (released 10.6.2012) Fixes: - checking: Catch any errors initializing the MIME database. Closes: SF bug #3528450 - checking: Fix writing temporary files. - checking: Properly handle URLs with user/password information. Closes: SF bug #3529812 Changes: - checking: Ignore URLs from local PHP files with execution directives of the form "". Prevents false errors when checking local PHP files. Closes: SF bug #3532763 - checking: Allow configuration of local webroot directory to enable checking of local HTML files with absolute URLs. Closes: SF bug #3533203 Features: - installation: Support RPM building with cx_Freeze. - installation: Added .desktop files for POSIX systems. - checking: Allow writing of a memory dump file to debug memory problems. 7.8 "Gangster Exchange" (released 12.5.2012) Fixes: - checking: Always use GET for Zope servers since their HEAD support is broken. Closes: SF bug #3522710 - installation: Install correct MSVC++ runtime DLL version for Windows. - installation: Install missing Python modules for twill, cssutils and HTMLTidy. Changes: - documentation: Made the --ignore-url documentation more clear. Patch from Charles Jones. Closes: SF bug #3522351 - installation: Report missing py2app instead of generating a Distutils error. Closes: SF bug #3522265 - documentation: Fix typo in linkcheckerrc.5 manual page. Closes: SF bug #3522846 Features: - installation: Add dependency declaration documentation to setup.py. Closes: SF bug #3524757 7.7 "Intouchables" (released 22.04.2012) Fixes: - checking: Detect invalid empty cookie values. Patch by Charles Jones. Closes: SF bug #3514219 - checking: Fix cache key for URL connections on redirect. Closes: SF bug #3514748 - gui: Fix update check when content could not be downloaded. Closes: SF bug #3515959 - i18n: Make locale domain name lowercase, fixing the .mo-file lookup on Unix systems. - checking: Fix CSV output with German locale. Closes: SF bug #3516400 - checking: Write correct statistics when saving results in the GUI. Closes: SF bug #3515980 Changes: - cmdline: Remove deprecated options --check-css-w3 and --check-html-w3. Features: - cgi: Added a WSGI script to replace the CGI script. 7.6 "Trkisch fr Anfnger" (released 31.03.2012) Fixes: - checking: Recheck extern status on HTTP redirects even if domain did not change. Patch by Charles Jones. Closes: SF bug #3495407 - checking: Fix non-ascii HTTP header handling. Closes: SF bug #3495621 - checking: Fix non-ascii HTTP header debugging. Closes: SF bug #3488675 - checking: Improved error message for connect errors to the ClamAV virus checking daemon. - gui: Replace configuration filename in options dialog. - checking: Honor the charset encoding of the Content-Type HTTP header when parsing HTML. Fixes characters displayed as '?' for non-ISO-8859-1 websites. Closes: SF bug #3388257 - checking: HTML parser detects and handles invalid comments of the form "". Closes: SF bug #3509848 - checking: Store cookies on redirects. Patch by Charles Jones. Closes: SF bug #3513345 - checking: Fix concatenation of multiple cookie values. Patch by Charles Jones. - logging: Encode comments when logging CSV comments. Closes: SF bug #3513415 Changes: - checking: Add real url to cache. Improves output for cached errors. - checking: Specify timeout for SMTP connections. Avoids spurious connect errors when checking email addresses. Closes: SF bug #3504366 Features: - config: Allow --pause and --cookiefile to be set in configuration file. 7.5 "Kukushka" (released 13.02.2012) Fixes: - checking: Properly handle non-ascii HTTP header values. Closes: SF bug #3473359 - checking: Work around a Squid proxy bug which resulted in not detecting broken links. Closes: SF bug #3472341 - documentation: Fix typo in the manual page. Closes: SF bug #3485876 Changes: - checking: Add steam:// URIs to the list of ignored URIs. Closes: SF bug #3471570 - checking: Deprecate the --check-html-w3 and --check-css-w3 options. The W3C checkers are automatically used if a local check library is not installed. - distribution: The portable version of LinkChecker does not write the configuration file in the user directory anymore. So a user can use this version on a foreign system without leaving any traces behind. Features: - gui: Add Ctrl-L shortcut to highlight the URL input. - gui: Support loading and saving of project files. Closes: SF bug #3467492 7.4 "Warrior" (released 07.01.2012) Fixes: - gui: Fix saving of check results as a file. Closes: SF bug #3466545, #3470389 Changes: - checking: The archive attribute of and is a comma-separated list of URIs. The value is now split and each URI is checked separately. - cmdline: Remove deprecated options. - configuration: The dictionary-based logging configuration is now used. The logging.conf file has been removed. - dependencies: Python >= 2.7 is now required Features: - checking: Add HTML5 link elements and attributes. 7.3 "Attack the block" (released 25.12.2011) Fixes: - configuration: Properly detect home directory on OS X systems. Closes: SF bug #3423110 - checking: Proper error reporting for too-long unicode hostnames. Closes: SF bug #3438553 - checking: Do not remove whitespace inside URLs given on the commandline or GUI. Only remove whitespace at the start and end. - cmdline: Return with non-zero exit value when internal program errors occurred. - gui: Fix saving of check results as a file. Changes: - gui: Display all options in one dialog instead of tabbed panes. Features: - gui: Add configuration for warning strings instead of regular expressions. The regular expressions can still be configured in the configuration file. - gui: Add configuration for ignore URL patterns. Closes: SF bug #3311262 - checking: Support parsing of Safari Bookmark files. 7.2 "Drive" (released 20.10.2011) Fixes: - checking: HTML parser now correctly detects character encoding for some sites. Closes: SF bug #3388291 - logging: Fix SQL output. Closes: SF bug #3415274, #3422230 - checking: Fix W3C HTML checking by using the new soap12 output. Closes: SF bug #3413022 - gui: Fix startup when configuration file contains errors. Closes: SF bug #3392021 - checking: Ignore errors trying to get FTP feature set. Closes: SF bug #3424719 Changes: - configuration: Parse logger and logging part names case insensitive. Closes: SF bug #3380114 - gui: Add actions to find bookmark files to the edit menu. Features: - checking: If a warning regex is configured, multiple matches in the URL content are added as warnings. Closes: SF bug #3412317 - gui: Allow configuration of a warning regex. 7.1 "A fish called Wanda" (released 6.8.2011) Fixes: - checking: HTML parser detects and handles stray "<" characters before end tags. - checking: Reset content type setting after loading HTTP headers again. Closes: SF bug #3324125 - checking: Remove query and fragment parts of file URLs. Fixes false errors checking sites on local file systems. Closes: SF bug #3308753 - checking: Do not append a stray newline character when encoding authentication information to base64. Fixes HTTP basic authentication. Closes: SF bug #3377193 - checking: Ignore attribute errors when printing the Qt version. - checking: Update cookie values instead of adding duplicate entries. Closes: SF bug #3373910 - checking: Send cookies in as few headers as possible. Closes: SF bug #3346972 - checking: Send all domain-matching cookies that apply. Closes: SF bug #3375899 - gui: Properly reset active URL count when checking stops. Closes: SF bug #3311270 Changes: - gui: Default to last URL checked in GUI (if no URL is given as commandline parameter). Closes: SF bug #3311271 - cgi: Removed FastCGI module. The normal CGI module should be sufficient. - doc: Document the list of supported warnings in the linkcheckerrc(5) man page. Closes: SF bug #3340449 Features: - checking: New option --user-agent to set the User-Agent header string sent to HTTP web servers. Note that this does not change or prevent robots.txt checking. Closes: SF bug #3325026 7.0 "Plots with a View" (released 28.5.2011) Fixes: - doc: Correct reference to RFC 2616 for cookie file format. Closes: SF bug #3299557 - checking: HTML parser detects and handles stray "<" characters. Closes: SF bug #3302895 - checking: Correct wrong import path in configuration file. Closes: SF bug #3305351 - checking: Only check warning patterns in parseable content. Avoids false errors downloading large binary files. Closes: SF bug #3297970 - checking: Correctly include dns.rdtypes.IN and dns.rdtypes.ANY submodules in Windows and OSX installers. Fixes false DNS errors. Closes: SF bug #3297235 Changes: - gui: Display status info into GUI main window instead of modal window. Closes: SF bug #3297252 - gui: Display warnings in result column. Closes: SF bug #3298036 - gui: Improved option dialog layout. Closes: SF bug #3302498 - doc: Document the ability to search for URLs with --warning-regex. Closes: SF bug #3297248 - checking: Support for a system configuration file has been removed. There is now only one user-configurable configuration file. - doc: Paginate linkchecker -h output when printing to console. Features: - logging: Colorize number of errors in text output logger. - checking: Support both Chromium and Google Chrome profile dirs for finding bookmark files. - gui: Remember last 10 checked URLs in GUI. Closes: SF bug #3297243 - gui: Display the number of selected rows as status message. Closes: SF bug #3297247 6.9 "Cowboy Bebop" (released 6.5.2011) Fixes: - gui: Correctly reset logger statistics. - gui: Fixed saving of parent URL source. - installer: Fixed portable windows version by not compressing DLLs. - checking: Catch socket errors when resolving GeoIP country data. Changes: - checking: Automatically allow redirections from URLs given by the user. - checking: Limit download file size to 5MB. SF bug #3297970 - gui: While checking, show new URLs added in the URL list view by scrolling down. - gui: Display release date in about dialog. Closes: SF bug #3297255 - gui: Warn before closing changed editor window. Closes: SF bug #3297245 - doc: Improved warningregex example in default configuration file. Closes: SF bug #3297254 Features: - gui: Add syntax highlighting for Qt editor in case QScintilla is not installed. - gui: Highlight check results and colorize number of errors. - gui: Reload configuration after changes have been made in the editor. Closes: SF bug #3297242 6.8 "Ghost in the shell" (released 26.4.2011) Fixes: - checking: Make module detection more robust by catching OSError. Changes: - gui: Print detected module information in about dialog. - gui: Close application on Ctrl-C. - checking: Ignore redirections if the scheme is not HTTP, HTTPS or FTP. - build: Ship Microsoft C++ runtime files directly instead of the installer package. - gui: Make QScintilla editor optional by falling back to a QPlainText editor. Features: - build: Support building a binary installer in 64bit Windows systems. - build: The Windows installer is now signed with a local self-signed certificate. - build: Added a Mac OS X binary installer. - network: Support getting network information on Mac OS X systems. 6.7 "Friendship" (released 12.4.2011) Fixes: - gui: Fix display of warnings in property pane. Closes: SF bug #3263974 - gui: Don't forget to write statistics when saving result files. - doc: Added configuration file locations in HTML documentation. - doc: Removed mentioning of old -s option from man page. - logging: Only write configured output parts in CSV logger. - logging: Correctly encode CSV output. Closes: SF bug #3263848 - logging: Don't print empty country information. - gui: Don't crash while handling internal error in non-main threads. Changes: - gui: Improved display of internal errors. - logging: Print more detailed locale information on internal errors. Features: - gui: Added CSV output type for results. - gui: Use Qt Macintosh widget style on OS X systems. - logging: Print recursion level in machine readable logger outputs xml, csv and sql. Allows filtering the output by recursion level. 6.6 "Coraline" (released 25.3.2011) Fixes: - gui: Really read system and user configuration file. - gui: Fix "File->Save results" command. Closes: SF bug #3223290 Changes: - logging: Add warning tag attribute in XML loggers. Features: - gui: Added a crash handler which displays exceptions in a dialog window. 6.5 "The Abyss" (released 13.3.2011) Fixes: - checking: Fix typo calling get_temp_file() function. Closes: SF bug #3196917 - checking: Prevent false positives when detecting the MIME type of certain archive files. - checking: Correct conversion between file URLs and encoded filenames. Fixes false errors when handling files with Unicode encodings. - checking: Work around a Python 2.7 regression in parsing certain URLs with paths starting with a digit. - cmdline: Fix filename completion if path starts with ~ - cgi: Prevent encoding errors printing to sys.stdout using an encoding wrapper. Changes: - checking: Use HTTP GET requests to work around buggy IIS servers sending false positive status codes for HEAD requests. - checking: Strip leading and trailing whitespace from URLs and print a warning instead of having errors. Also all embedded whitespace is stripped from URLs given at the commandline or the GUI. Closes: SF bug #3196918 Features: - configuration: Support reading GNOME and KDE proxy settings. 6.4 "The Sunset Limited" (released 20.2.2011) Fixes: - checking: Do not remove CGI parameters when joining URLs. - checking: Correctly detect empty FTP paths as directories. - checking: Reuse connections more than once and ensure they are closed before expiring. - checking: Make sure "ignore" URL patterns are checked before "nofollow" URL patterns. Closes: SF bug #3184973 - install: Properly include all linkcheck.dns submodules in the .exe installer. - gui: Remove old context menu action to view URL properties. - gui: Disable viewing of parent URL source if it's a directory. Changes: - gui: Use Alt-key shortcuts for menu entries. - checking: Improved thread locking and reduce calls to time.sleep(). - cmdline: Deprecate the --priority commandline option. Now the check process runs with normal priority. - cmdline: Deprecate the --allow-root commandline option. Root privileges are now always dropped. - cmdline: Deprecate the --interactive commandline option. It has no effect anymore. Features: - checking: Added support for Google Chrome bookmark files. - gui: Preselect filename on save dialog when editing file:// URLs. Closes: SF bug #3176022 - gui: Add context menu entries for finding Google Chrome and Opera bookmark files. 6.3 "Due Date" (released 6.2.2011) Fixes: - install: Fixed the install instructions. Closes: SF bug #3153484 - logging: Enforce encoding error policy when writing to stdout. - checking: Prevent error message from Geoip by using the correct API function when no city database is installed. - checking: Properly detect case where IPv6 is not supported. Closes: SF bug #3167249 Changes: - gui: Detect local or development versions in update check. 6.2 "Despicable Me" (released 6.1.2011) Changes: - checking: Parse PHP files recursively. - gui: Remove reset button from option dialog. Features: - gui: Add update check for newer versions of LinkChecker. 6.1 "Christmas Vacation" (released 23.12.2010) Fixes: - checking: Fix broken anchor checking. Closes: SF bug #3140765 - checking: Properly detect filenames with spaces as internal links when given as start URL. - logging: Allow Unicode strings to be written to stdout without encoding errors on Unix systems. - logging: Fix missing content type for cached URLs. - gui: Reset statistics before each run. Changes: - install: Compress Windows installer with upx, saving some Bytes. Features: - gui: Add URL input context menu action to paste Firefox bookmark file. - install: Added a portable package for Windows. 6.0 "Kung Fu Panda Holiday Special" (released 19.12.2010) Fixes: - checking: Fall back to HTTP GET requests when the connection has been reset since some servers tend to do this for HEAD requests. Closes: SF bug #3114622 - gui: Activate links in property dialog. - gui: Fix sorting of columns in URL result list. Closes: SF bug #3131401 - checking: Fix wrong __init__ call to URL proxy handler. Closes: SF bug #3118254 - checking: Catch socket errors (for example socket.timeout) when closing SMTP connections. Changes: - dependencies: Require and use Python 2.6. - cmdline: Removed deprecated options --no-anchor-caching and --no-proxy-for. - config: Remove backwards compatilibity parsing and require the new multiline configuration syntax. - logging: Use codecs module for proper output encoding. Closes: SF bug #3114624 - checking: The maximum file size of FTP files is now limited to 10MB. - checking: Remove warning about using Unicode domains which are more widely supported now. - logging: The unique ID of an URL is not printed out anymore. Instead the cache URL key should be used to uniquely identify URLs. - gui: Display URL properties in main window instead of an extra dialog. Features: - logging: More statistic information about content types and URL lengths is printed out. - gui: Store column widths in registry settings. - gui: Add ability to save results to local files with File->Save. - gui: Assume the entered URL starts with http:// if it has no scheme specified and is not a valid local file. - gui: Display check statistics in main window. - gui: There is now a clear button in the URL input field if any text has been written to it. 5.5 "Red" (released 20.11.2010) Fixes: - checking: Do not check content of already cached URLs. Closes: SF bug #1720083 - checking: Do not parse URL CGI part recursively, avoiding maximum recursion limit errors. Closes: SF bug #3096115 - logging: Avoid error when logger fields "intro" or "outro" are configured. - logging: Correctly quote edge labels of graph output formats and remove whitespace. - checking: Make sure the check for external domain is done after all HTTP redirections. - checking: Check for allowed content read before trying to parse anchors in HTML file. Closes: SF bug #3110569 Changes: - cmdline: Don't log a warning if URL has been redirected. Closes: SF bug #3078820 - checking: Do not print warnings for HTTP -> HTTPS and HTTPS -> HTTP redirects any more. - logging: Changed comment format in GML output to be able to load the graph in gephi. - gui: Remove timeout and thread options. - checking: Do not report irc:// hyperlinks as errors, ignore them instead. Closes: SF bug #3106302 Features: - gui: Add command to save the parent URL source in a local file. - gui: Show configuration files in option dialog and allow them to be edited. Closes: SF bug #3102201 - gui: Added dialog to show detailed URL properties on double click. - gui: Store GUI options in registry settings. 5.4 "How to train your dragon" (released 26.10.2010) Fixes: - gui: Enable the cancel button again after it has been clicked and disabled. - checking: Fix printing of active URLs on Ctrl-C. - checking: Check for allowed content read before trying to parse robots.txt allowance. - gui: Prevent off-screen window position. Closes: SF bug #3025284 Changes: - gui: Display cancel message in progress window. - gui: Use separate debug log window. - install: Copy and execute the Microsoft Visual C runtime DLL installer. This solves startup error on WinXP systems that don't have this DLL installed. Closes: SF bug #3025284 - checking: Tune timeout values to close threads faster on exit. Closes: SF bug #3087944 - config: Authentication password entries are optional and if missing have to be entered at the commandline. Features: - gui: Added "View parent URL online" context menu action to display source in text editor window. Closes: SF bug #3040378 - gui: Read default options from configuration file. Closes: SF bug #2931320 - config: Added configuration file option for the --cookies command line option. - http: Allow specifying a login URL in the configuration file which gets visited before checking submits login data. Closes: SF bug #3041527 5.3 "Inception" (released 29.9.2010) Fixes: - ftp: Fix support for FTP ports other than the default. - build: Use _WIN32 instead of WIN32 define to detect Windows systems. Closes: SF bug #2978524 - http: Send correct host header when using proxies. Thanks Jason Martin for the patch. Closes: SF bug #3035754 - file: Prevent truncation of UNC paths on Windows systems. Closes: SF bug #3017391 - url: Work around a Python bug cutting off characters when joining an URL that starts with semicolon. Closes: SF bug #3056136 - gui: Enable tree widget items to make them selectable. This makes the right-click context menu work again. Closes: SF bug #3040377 Changes: - checking: Caches are now size-restricted to limit the memory usage. - logging: Use more memory-efficient wire-format for UrlBase, using __slots__. Closes: SF bug #2976995 - checking: Get size from Content-Length HTTP header and for local files from stat(2) so size information is available without downloading the content data. - checking: Remove the unnormed URL warning. URLs can be written in more than one way and there is no norm. Closes: SF bug #1575800 - checking: Add "skype:" to list of ignored URL schemes. Closes: SF bug #2989086 - logging: Prefer the element content as name instead of the title attribute. Closes: SF bug #3023483 - logging: Use semicolon as default separator for CSV files so it opens in Excel initially. - checking: Allow redirections of external URLs if domain stays the same. Closes: SF bug #3024394 - cmdline: The --password option now reads a password from stdin instead taking it from the commandline. - gui: Change registry base key to avoid spydoctor alert. Old keys have to be deleted by hand though. Closes: SF bug #3062161 Features: - ftp: Detect and support UTF-8 filename encoding capability of FTP servers. - checking: Added new warning to check if content size is zero. - install: Remove Windows registry keys on uninstall. - checking: Do not fall back to GET when no recursion is requested on single pages. This allows to check pages with a HEAD request even if robots.txt disallows to get the page content. - checking: detect and warn when obfuscated IP addresses are found. - gui: Add "Copy to clipboard" context menu item to copy an URL to the system clipboard. - checking: Support the pygeoip package to display country information on windows systems. 5.2 "11:14" (released 7.3.2010) Fixes: - logging: Use default platform encoding instead of hardcoded one of iso-8859-1. Closes: SF bug #2770077 - dns: Use /dev/urandom instead of /dev/random to get initial seed on Linux machines since the last one can block indefinitely. Closes: SF bug #2901667 - http: Retry if server closed connection and sent an empty status line. Fixes the "BadStatusLine" errors. - http: Prevent UnicodeDecodeError on redirection by ensuring that the redirected URL will be Unicode encoded. - checking: Prevent UnicodeDecodeError in robots.txt parser by encoding the linkchecker useragent string. - installer: Add commandline executable to Windows installer. Closes: SF bug #2903257 - http: Warn about permanent redirections even when redirected URL is outside of the domain filter. Closes: SF bug #2920182 - mailto: An empty email-address is syntactically allowed according to RFC2368. So the syntax error about missing email-addresses gets demoted to a warning. Closes: SF bug #2910588 - cmdline: Expand tilde (~) in filenames given with the --config option. Changes: - cmdline: disabled and deprecated the --no-proxy-for option. Use the $no_proxy environment variable instead. - dns: Updated dnspython module from upstream version 1.8.1. - checking: Improved HTML parsing speed: a) The parsers for HTML title and robots.txt meta tags stop after seeing a tag. b) Anchor references are not always parsed, but onl when the--anchor option was given. c) Found HTML links are not queued after parsing the whole file, but directly when found. This also saves some memory. Features: - checking: Check hyperlinks of Word documents. Needs pywin32 installed. - http: Allow and support HTTPS proxies. 5.1 "Let the right one in" (released 04.08.2009) Fixes: - logging: The content size of downloads is now shown again. - logging: The CSV logger does not crash anymore when only parts of log output was configured Closes: SF bug #2806790 - http: Fixed persistent connection handling: retry connecting to HTTP servers which close persistent connections unexpectedly. - bookmarks: correctly read the bookmark title from Mozilla places.sqllite - checking: ignore the fragment part (ie. the anchor) of URIs when getting and caching HTTP content; follows the HTTP/1.1 specification which does not include fragments in the protocol. Thanks to Martin von Gagern for pointing this out. This also deprecates the --no-anchor-caching option which will be removed in future releases. Closes: SF bug #2784996 - checking: Prefer to encode spaces with %20 instead of + to be sure mailto: URLs are understood by email clients. Closes: SF bug #2820773 - checking: Allow digits at end of domain names. Changes: - logging: Switch default output encoding of loggers to UTF-8, except the text logger which also honors the system settings. Closes: SF bug #2579899 - logging: Make output more concise by not logging duplicate cached URLs. - nntp: Only retry 3 instead of 5 times to connect to busy NNTP servers. - cmdline: The command line script exits with error only when errors or warnings are printed. Previously it exited with error status even when all warnings were ignored. Closes: SF bug #2820812 Features: - email: Added email syntax checking. Closes: SF bug #2595437 - gui: Improved progress dialog in GUI client: show active and queued URLs. - gui: Added right-click context menu for logged URLs. - nntp: Output welcome message from NNTP servers as info. - http: Honor the no_proxy environment variable. - config: the system configuration is copied to the user configuration at ~./linkchecker/linkcheckerrc if it does not exist yet. - logging: the loggers now have an additional field "ID" which prints a unique ID for each logged URL. 5.0.2 "All the boys love Mandy Lane" (released 13.2.2009) * Properly detect location of the log configuration file in the Windows binary .exe. Closes: SF bug #2564674 * Install locale .mo files in the Windows binary .exe 5.0.1 "Slumdog Millionaire" (released 31.1.2009) * Remove unit tests from distribution to avoid antivirus software alarms with the virus filter tests. Closes: SF bug #2537822 * Updated dnspython module from upstream. Changed: linkcheck/dns/*, tests/dns/* 5.0 "Iron Man" (released 24.1.2009) * Require and use Python >= 2.5. Type: feature Changed: *.py * Send HTTP Referer header for both http and https URLs. Type: feature Changed: linkcheck/checker/httpurl.py * The HTML and CSS syntax check now only applies to URLs which match those given on the command line. This makes checking of personal pages easier. Type: feature Changed: linkcheck/checker/urlbase.py * Added online HTML and CSS syntax checks using W3C validators. Implemented as commandline options --check-html-w3 and --check-css-w3. Type: feature Changed: linkchecker, linkcheck/checker/urlbase.py * Added ability to scan URL content with ClamAV virus scanner. Implemented as commandline option --scan-virus. Type: feature: Changed: linkchecker, linkcheck/checker/urlbase.py Added: linkcheck/clamav.py * Improved network interface detection on POSIX systems. Type: bugfix Added: linkcheck/network/* * Improved graph output: print labels as node names. Thanks to Jan Weiss for the initial idea. Type: feature Changed: linkcheck/logger/{dot,gml,gxml}.py Added: linkcheck/logger/graph.py * Add support for setuptools and thus Python eggs in the setup.py script. This should fix installation errors for generated .egg files. Type: feature Closes: SF bug #1985509 * Support parsing of HTML pages served with application/xhtml+xml content type. Type: bugfix Closes: SF bug #1994104 * Support reading URLs from stdin in the commandline interface. Type: feature Closes: SF bug #2013873, #2013874 Changed: linkchecker * Improved filename recognition on Windows systems. Type: bugfix Changed: linkcheck/checker/fileurl.py * Fix error encoding non-ASCII robots.txt content. Makes some sites like wikipedia.org accessible with LinkChecker. Type: bugfix Changed: linkcheck/robotparser2.py * Fix off-by-one error in cookie domain matching code. Prevented some cookie files to work properly. Type: bugfix Changed: linkcheck/cookies.py Closes: SF bug #2016451 * Improved double Ctrl-C abort on Unix and Windows platforms. Type: feature Changed: linkcheck/director/__init__.py * Support reading Firefox 3 bookmark files in SQLite format. Type: feature Changed: linkcheck/checker/fileurl.py * Handle non-Latin1 filenames when checking local directories. Type: bugfix Closes: SF bug #2093225 Changed: linkcheck/checker/fileurl.py * Use configured proxy when requesting robots.txt, especially honor the noproxy values. Type: bugfix Closes: SF bug #2091297 Changed: linkcheck/robotparser2.py, linkcheck/cache/robots_txt.py, linkcheck/checker/httpurl.py * Added new --complete option; making --verbose less chatty. Type: feature Closes: SF #2338973 Changed: linkchecker, linkcheck/configuration/__init__.py * Remove gopher: URL checking. Type: feature Changed: linkcheck/checker/unkonwnurl.py Removed: linkcheck/checker/gopherurl.py 4.9 "Michael Clayton" (released 25.4.2008) * Parse Shockwave Flash (SWF) for URLs to check Type: feature Changed: linkcheck/checker/urlbase.py * Don't parse is not allowed anymore in single-line JavaScript comments in HTML data. Type: feature Changed: linkcheck/HtmlParser/htmllex.[lc], linkcheck/tests/test_parser.py * Revamp the threading algorithm by using a URL queue, with a constant number of consumer threads called 'workers'. This fixes the remaining "dequeue mutated during iteration" errors. Type: feature Changed: *.py * The default intern pattern matches both http: and https: schemes now. Type: feature Changed: linckheck/checker/internpaturl.py * If the robots.txt connection times out, don't bother to check the URL but report an error immediately. Avoids having the timeout twice. Type: feature Changed: linkcheck/robotparser2.py * DNS lookups for HTTP links are now cached. Type: feature Changed: linkcheck/httplib2.py Added: linkcheck/cache/addrinfo.py * Added timeout value option to the configuration file. Type: feature Changed: linkcheck/configuration/confparse.py, config/linkcheckerrc * New option --cookiefile to set initial cookie values sent to HTTP servers. Type: feature Changed: linkchecker, linkcheck/configuration/__init__.py, linkcheck/checker/httpurl.py, linkcheck/cookies.py * The --pause option delays requests to the same host, and is not required to disable threading to do that. Type: bugfix Changed: linkcheck/cache/connection.py, linkcheck/checker/urlbase.py, linkcheck/directory/__init__.py * Honor the "Crawl-delay" directive in robots.txt files. Type: feature Changed: linkcheck/robotparser2.py, linkcheck/checker/httpurl.py, linkcheck/cache/robots_txt.py, linkcheck/cache/connection.py, * Merge IgnoredUrl and ErrorUrl into UnknownUrl. Enables caching on invalid URLs, plus the ability to first check for external URL patterns. Type: bugfix Changed: linkcheck/checker/__init__.py Removed: linkcheck/checker/{ignored,error}url.py Added: linkcheck/checker/unknownurl.py * Convert the "label too long" domain name parse error into a more friendly error message. Type: bugfix Changed: linkcheck/checker/{__init__,urlbase,httpurl,fileurl}.py, linkchecker 3.4 "The Chumscrubbers" (released 4.2.2006) * Ignore decoding errors when retrieving the robots.txt URL. Type: bugfix Changed: linkcheck/robotparser2.py * On HTTP redirects, cache all the encountered URLs, not just the initial one. Type: feature Changed: linkcheck/checker/{urlbase,httpurl,cache}.py * Fixed the Cookie parsing and sending. Type: bugfix Changed: linkcheck/checker/cache.py Added: linkcheck/cookies.py * The psyco optimizer now has a maximum memory limit. Type: feature Changed: linkchecker * The checker did not recurse into command line URLs that had upper case characters. Type: bugfix Changed: linkcheck/checker/__init__.py Closes: SF bug #1413162 * Fix a possible thread race condition by checking the return value of the lock.acquire() method. Type: bugfix Changed: linkcheck/decorators.py 3.3 "Four Brothers" (released 14.10.2005) * Fix parsing of ignore and nofollow in configuration files. Type: bugfix Changed: linkcheck/configuration.py Closes: SF bug #1311964, #1270783 * Ignore refresh meta content without a recognizable URL. Type: bugfix Changed: linkcheck/linkparse.py Closes: SF bug #1294456 * Catch CGI syntax errors in mailto: URLs, and add an appropriate warning about the error. Type: bugfix Changed: linkcheck/checker/mailtourl.py Closes: SF bug #1290563 * Initialize the i18n on module load time, so one does not have to call init_i18n() manually anymore. Fixes parts in the code (ie. the CGI script) that forgot to do this. Type: feature Changed: linkcheck/__init__.py Closes: SF bug #1277577 * Compress libraries in the .exe installer with UPX compressor. Type: feature Changed: setup.py * Ensure that base_url is Unicode for local files. Type: bugfix Changed: linkcheck/checker/fileurl.py Closes: Debian bug #332870 * The default encoding for program and logger output will be the preferred encoding now. It is determined from your current locale system settings. Type: feature Changed: linkchecker, linkcheck/checker/__init__.py, linkcheck/i18n.py, linkcheck/logger/__init__.py * Improved documentation about recursion and proxy support. Type: documentation Changed: linkchecker, doc/en/documentation.txt, doc/{en,de}/linkchecker.1 * Make sure that given proxy values are reasonably well-formed. Else abort checking of the current URL. Type: feature Changed: linkcheck/checker/proxysupport.py * Correctly catch internal errors in the check URL loop, and disable raising certain exceptions while the abort routine finishes up. Fixes the "dequeue mutated during iteration" errors. Type: bugfix Changed: linkcheck/checker/{__init__,consumer}.py Closes: SF bug #1325570, #1312865, #1307775, #1292919, #1264865 3.2 "Kiss kiss bang bang" (released 3.8.2005) * Fixed typo in redirection handling code. Type: bugfix Changed: linkcheck/checker/httpurl.py * Handle all redirections to different URL types, not just HTTP -> non-HTTP. Type: bugfix Changed: linkcheck/checker/httpurl.py * Workaround a urllib2.py bug raising ValueError on some failed HTTP authorisations. Type: bugfix Closes: SF bug #1250555 Changed: linkcheck/robotparser2.py * Fix invalid import in DNS resolver. Type: bugfix Changed: linkcheck/dns/resolver.py 3.1 "Suspicious" (released 18.7.2005) * Updated documentation for the HTML parser. Type: feature Changed: linkcheck/HtmlParser/* * Added new DNS debug level and use it for DNS routines. Type: feature Changed: linkcheck/__init__.py, doc/en/linkchecker.1, linkcheck/dns/{ifconfig,resolver}.py * Use tags for different LinkChecker warnings and allow them to be filtered with a configuration file entry. Type: feature Changed: linkchecker, linkcheck/checker/*.py, linkcheck/configuration.py * Add compatibility fix for HTTP/0.9 servers, from Python CVS. Type: bugfix Changed: linkcheck/httplib2.py * Add buffer flush fix for gzip files, from Python CVS. Type: bugfix Changed: linkcheck/gzip2.py * Do not cache URLs where a timeout or unusual error occurred. This way they get re-checked. Type: feature Changed: linkcheck/checker/{__init__, urlbase}.py * For HTTP return codes, try to use the official W3C name when it is defined. Type: feature Changed: linkcheck/checker/httpurl.py * Fix detection code of supported GCC command line options. this fixes a build error on some Unix systems (eg. FreeBSD). Type: bugfix Closes: SF bug #1238906 Changed: setup.py * Renamed the old "xml" output logger to "gxml" and added a new "xml" output logger which writes a custom XML format. Type: feature Changed: linkchecker, linkcheck/logger/*xml*.py * Use correct number of checked URLs in status output. Type: bugfix Closes: SF bug #1239943 Changed: linkcheck/checker/consumer.py 3.0 "The Jacket" (released 8.7.2005) * Catch all check errors, not just the ones inside of URL checking. Type: bugfix Changed: linkcheck/checker/__init__.py * Ensure that the name of a newly created thread is ASCII. Else there can be encoding errors. Type: bugfix Changed: linkcheck/strformat.py, linkcheck/checker/consumer.py, linkcheck/threader.py * Use our own gzip module to cope with incomplete gzip streams. Type: bugfix Closes: SF bug #1158475 Changed: linkcheck/checker/httpurl.py Added: linkcheck/gzip2.py * Fix hard coded python.exe path in the batch file linkchecker.bat. Type: bugfix Closes: SF bug #1206858 Changed: setup.py, install-linkchecker.py * Allow empty relative URLs. Note that a completely missing URL is still an error (ie. is valid, is an error). Type: bugfix Closes: SF bug #1217397 Changed: linkcheck/linkparse.py, linkcheck/logger/*.py, linkcheck/checker/urlbase.py * Added checks for more URL entries, especially favicon check was added. Type: feature Changed: linkcheck/linkparse.py * Limit memory consumption of psyco optimizer. Type: feature Changed: linkchecker * Always norm the URL before sending a request. Type: bugfix Changed: linkcheck/checker/urlbase.py * Send complete email address on SMTP VRFY command. Avoids a spurious warning about incomplete email addresses. Type: bugfix Changed: linkcheck/checker/mailtourl.py * The old intern/extern URL configuration has been replaced with a new and hopefully simpler one. Please see the documentation on how to upgrade to the new option syntax. Type: feature Changed: linkchecker, linkcheck/*.py * Honor XHTML in tag browser. Type: bugfix Closes: SF bug #1217356 Changed: linkcheck/linkparse.py * Catch curses.setupterm() errors. Type: bugfix Closes: SF bug #1216092 Changed: linkcheck/ansicolor.py * Only call _optcomplete bash completion function when it exists. Type: bugfix Closes: Debian bug #309076 Changed: config/linkchecker-completion * If a default config file (either /etc/linkchecker/linkcheckerrc or ~/.linkchecker/linkcheckerrc) does not exist it is not added to the config file list. Type: bugfix Changed: linkcheck/configuration.py * The default output encoding is now that of your locale, and not the hardcoded iso-8859-15 anymore. Type: feature Closes: Debian bug #307810 Changed: linkcheck/logger/__init__.py * Do not generate an empty user config dir ~/.linkchecker by default, only when needed. Type: feature Closes: Debian bug #307876 Changed: linkchecker * Redundant dot path at beginning of relative urls are now removed. Type: feature Changed: linkcheck/url.py, linkcheck/tests/test_url.py * Displaying warnings is now the default. One can disable warnings with the --no-warnings option. The old --warnings option is deprecated. Type: feature Changed: linkchecker, linkcheck/configuration.py * CGI parameters in URLs are now properly splitted and normed. Type: bugfix Changed: linkcheck/url.py * The number of encountered warnings is printed on program end. Type: feature Changed: linkcheck/logger/{text,html}.py * The deprecated --status option has been removed. Type: feature Changed: linkchecker * New option --disable-psyco to disable psyco compilation regardless if it is installed. Type: feature Changed: linkchecker * Since URL aliases from redirections do not represent the real URL with regards to warnings, the aliases are no longer cached. Type: bugfix Changed: linkcheck/checker/cache.py, linkcheck/checker/httpurl.py * The ignored url type honors now intern/extern filters. Type: bugfix Changed: linkcheck/checker/ignoreurl.py Closes: SF #1223956 2.9 "Sweat" (released 22.4.2005) * Use collections.deque object for incoming URL list. This is faster than a plain Python list object. Type: optimization Changed: linkcheck/checker/cache.py * Updated spanish translation, thanks to Servilio Afre Puentes. Type: feature Changed: po/es.po 2.8 "Robots" (released 8.4.2005) * Correct AttributeError in blacklist logger. Type: bugfix Closes: SF bug #1173823 Changed: linkcheck/logger/blacklist.py * Do not enforce an optional slash in empty URI paths. This resulted in spurious warnings. Closes: SF bug #1173841 Changed: linkcheck/url.py, linkcheck/tests/test_url.py * On NT-derivative Windows systems, the command line scripts is now named "linkchecker.bat" to facilitate execution. Type: feature Changed: setup.py, install-linkchecker.py, doc/en/index.txt * Use pydoc.pager() in strformat.paginate() instead of rolling out our own paging algorithm. Type: feature Changed: linkcheck/strformat.py 2.7 "Million Dollar Baby" (released 30.3.2005) * When a host has no MX record, fall back to A records as the mail host. Type: bugfix Changed: linkcheck/checker/mailtourl.py * Do not split CGI params on semicolons. This is wrong of course, but not supported by all servers. A later version of the CGI parser engine will split and re-join semicolons. Type: bugfix Changed: linkcheck/url.py * Make sure that URLs are always Unicode strings and not None. Type: bugfix Closes: SF bug #1168720 Changed: linkcheck/linkparse.py, linkcheck/containers.py * Fix the detection of persistent HTTP connections. Type: bugfix Changed: linkcheck/checker/httpheaders.py * HTTP connections with pending data will not be cached. Type: bugfix Changed: linkcheck/checker/httpurl.py * Add all URL aliases to the URL cache to avoid recursion. This also changes some invariants about what URLs are expected to be in the cache. Type: bugfix Changed: linkcheck/checker/cache.py 2.6 "Lord of the Rings" (released 15.3.2005) * Run with low priority. New option --priority to run with normal priority. Type: feature Changed: linkchecker, linkcheck/threader.py * If GeoIP Python wrapper is installed, log the country name as info. Type: feature Changed: linkcheck/checker/consumer.py Added: linkcheck/checker/geoip.py * New option --no-proxy-for that lets linkchecker contact the given hosts directly instead of going through a proxy. Also configurable in linkcheckerrc Type: feature Changed: linkchecker, linkcheck/checker/proxysupport.py, linkcheck/configuration.py * Give a useful error message for syntax errors in regular expressions. Type: bugfix Changed: linkchecker, linkcheck/configuration.py * Accept quoted urls in CSS attributes. Type: bugfix Changed: linkcheck/linkparse.py * Eliminate duplicate link reporting in the link parser. Type: bugfix Changed: linkcheck/linkparse.py * Do not send multiple Accept-Encoding headers. Type: bugfix Changed: linkcheck/checker/httpurl.py * Avoid deadlocks between the cache and the queue lock. Type: bugfix Changed: linkcheck/checker/consumer.py, linkcheck/checker/cache.py Added: linkcheck/lock.py * Always reinitialize stored HTTP headers on redirects; prevents a false alarm about recursive redirects. Type: bugfix Changed: linkcheck/checker/httpurl.py 2.5 "Spanglish" (released 4.3.2005) * Added spanish translation, thanks to Servilio Afre Puentes. Type: feature Changed: po/Makefile Added: po/es.po * Ignore a missing locale/ dir and fall back to the default locale instead of crashing. Type: bugfix Changed: linkcheck/i18n.py * Since profile.py and pstats.py have been removed from some Python standard installations (eg. Debian GNU/Linux), make their usage optional. Using --profile without an available profile.py prints a warning and runs linkchecker without profiling. Using --viewprof without an available pstats.py prints an error and exits. Type: bugfix Changed: linkchecker * Ensure stored result, info and warning strings are always Unicode. Else there might be encoding errors. Type: bugfix Closes: SF bug #1143553 Changed: linkcheck/checker/{urlbase,httpurl,ftpurl}.py, linkcheck/strformat.py * Fix -h help option on Windows systems Type: bugfix Closes: SF bug #1149987 Changed: linkchecker 2.4 "Kitchen stories" (released 9.2.2005) * Work around a Python 2.4 bug when HTTP 302 redirections are encountered in urllib2. Type: bugfix Changed: linkcheck/robotparser2.py * Be sure to use Unicode HTML parser messages. Type: bugfix Changed: linkcheck/linkparse.py * Make sure that FTP connections are opened when they are reused. Else open a new connection. Type: bugfix Changed: linkcheck/checker/ftpurl.py * Added '!' to the list of unquoted URL path characters. Type: bugfix Changed: linkcheck/url.py, linkcheck/tests/test_url.py * Fix Windows path name for network paths. Type: bugfix Closes: SF bug #1117839 Changed: linkcheck/checker/fileurl.py * Regularly remove expired connections from the connection pool. Type: feature Changed: linkcheck/checker/pool.py * Documentation and pylint cleanups. Type: feature Changed: linkcheck/*.py 2.3 "Napoleon Dynamite" (released 3.2.2005) * Use and require Python >= 2.4. Type: feature Changed: doc/install.txt, linkcheck/__init__.py, some scripts * Add square brackets ([]) to the list of allowed URL characters that do not need to be quoted. Type: bugfix Changed: linkcheck/url.py * Document the return value of the linkchecker command line script in the help text and man pages. Type: documentation Changed: linkchecker, doc/{en,de,fr}/linkchecker.1 * Always write the GML graph beginning, not just when "intro" field is defined. Type: bugfix Changed: linkcheck/logger/gml.py * Added DOT graph format output logger. Type: feature Added: linkcheck/logger/dot.py Changed: linkcheck/logger/__init__.py, linkcheck/configuration.py, linkchecker * Added ftpparse module to parse FTP LIST output lines. Type: feature Added linkcheck/ftpparse/* Changed: setup.py, linkcheck/checker/ftpurl.py * Ignore all errors when closing SMTP connections. Type: bugfix Changed: linkcheck/checker/mailtourl.py * Do not list FTP directory contents when they are not needed. Type: bugfix Changed: linkcheck/checker/ftpurl.py * Added connection pooling, used for HTTP and FTP connections. Type: feature Added: linkcheck/checker/pool.py Changed: linkcheck/checker/{cache, httpurl, ftpurl}.py * The new per-user configuration file is now stored in ~/.linkchecker/linkcheckerrc. Type: feature Changed: linkchecker, linkcheck/configuration.py, doc/{de,en,fr}/*.1 * The new blacklist output file is now stored in ~/.linkchecker/blacklist. Type: feature Changed: linkchecker, linkcheck/configuration.py, doc/{de,en,fr}/*.1 * Start the log output before appending new urls to the consumer since this can trigger logger.new_url(). Type: bugfix Changed: linkcheck/checker/{__init__, consumer}.py * Fix crash when using -t option. Type: bugfix Changed: linkchecker * Updated french translation of linkchecker, thanks to Yann Verley. Type: feature Changed: po/fr.po, doc/fr/linkchecker.1 2.2 "Cube" (released 25.01.2005) * CSV log format changes: - default separator is now a comma, not a semicolon - the quotechar can be configured and defaults to a double quote - write CSV column headers as the first data row (thanks to Hartmut Goebel) Type: feature Changed: linkcheck/logger/csvlog.py * Support bzip-compressed man pages in RPM install script. From Hartmut Goebel. Type: feature Changed: install-rpm.sh * HTML parser updates: - supply and use Py_CLEAR macro - only call set_encoding function if tag name is 'meta' Type: feature Changed: linkcheck/HtmlParser/* * Changed documentation format for epydoc. Type: documentation Changed: *.py * Fix FTP error message display crash. Type: bugfix Changed: linkcheck/checker/ftpurl.py * Ask before overwriting old profile data with --profile. Type: feature Changed: linkchecker * When searching for link names, limit the amount of data to look at to 256 characters. Do not look at the complete content anymore. This speeds up parsing of big HTML files significantly. Type: optimization Changed: linkcheck/linkparse.py * Support Psyco >= 1.4. If you installed older versions of Psyco, a warning is printed. Type: feature Changed: linkchecker, doc/install.txt * The build script setup.py uses -std=gnu99 when using GNU gcc compilers. This gets rid of several compile warnings. Type: feature Changed: setup.py * Correct the sent User-Agent header when getting robots.txt files. Added a simple robots.txt example file. Type: bugfix Changed: linkcheck/robotparser2.py Added: doc/robots.txt * Updated the included linkcheck/httplib2.py from the newest httplib.py found in Python CVS. Type: feature Changed: linkcheck/httplib2.py * Do not install unit tests. Only include them in the source distribution. Type: feature Changed: MANIFEST.in, setup.py 2.1 "Shogun Assassin" (released 11.1.2005) * Added XHTML support to the HTML parser. Type: feature Changed: linkcheck/HtmlParser/* * Support plural forms in gettext translations. Type: feature Changed: po/*.po* * Remove intern optcomplete installation, and make it optional to install, since it is only needed on Unix installations using bash-completion. Type: feature Changed: linkchecker, config/linkchecker-completion Removed: linkcheck/optcomplete.py * Minor enhancements in url parsing. Type: feature Changed: linkcheck/url.py * Sort according to preference when checking MX hosts so that preferred MX hosts get checked first. Type: bugfix Changed: linkcheck/checker/mailtourl.py * If mail VRFY command fails, print a warning message. Type: feature Changed: linkcheck/checker/mailtourl.py 2.0 "I Kina spiser de hunde" (released 7.12.2004) * Regenerate the HTML parser with new Bison version 1.875d. Also use the now supported Bison memory macros YYMALLOC and YYFREE. Type: feature Changed: linkcheck/HtmlParser/htmlparse.y * Updated installation and usage documentation. Type: documentation Changed: doc/install.txt, doc/index.txt * Added comment() method to loggers for printing comments. Type: feature Changed: linkcheck/logger/*.py * Updated and translated manpages. French translation from Yann Verley. German translation from me ;) Type: documentation Added: doc/de/linkchecker.de.1, doc/fr/linkchecker.fr.1 Changed: doc/en/linkchecker.1 * Fix mailto: URL norming by splitting the query type correctly. Type: bugfix Changed: linkcheck/url.py * Encode all output strings for display. Type: bugfix Changed: linkchecker * Accept -o option logger type as case independent string. Type: feature Changed: linkchecker * Internal Unicode handling fixed. Type: bugfix Changed: linkcheck/url.py, linkcheck/checker/*.py * Use correct FTP directory list parsing. Type: bugfix Changed: linkcheck/checker/ftpurl.py 2.0rc2 "El dia de la bestia" (released 20.11.2004) * encode version string for --version output Type: bugfix Closes: SF bug #1067915 Changed: linkchecker * Added shell config note with --home install option. Type: documentation Closes: SF bug #1067919 Changed: doc/install.txt * Recheck robots.txt allowance and intern/extern filters for redirected URLs. Type: bugfix Closes: SF bug #1067914 Changed: linkcheck/checker/httpurl.py * Updated the warning and info messages to be always complete sentences. Type: feature Changed: linkcheck/checker/*.py, po/*, linkcheck/ftests/*.py, linkcheck/ftests/data/*.result * Added missing script_dir to the windows installer script. Use python.exe instead of pythonw.exe and --interactive option to call linkcheck script. Add Documentation link to the programs group. Type: bugfix Changed: install-linkchecker.py 2.0rc1 "The Incredibles" (released 16.11.2004) * Only instantiate SSL connections if SSL is supported Type: bugfix Changed: linkcheck/checker/httpurl.py * Close all opened log files. Type: bugfix Changed: linkcheck/logger/*.py * All loggers have now an output encoding. Valid encodings are listed in http://docs.python.org/lib/node127.html. The default encoding is "iso-8859-15". Type: feature Changed: linkcheck/logger/*.py * The --output and --file-output parameters can specify the encoding now. The documentation has been updated with this change. Type: feature Changed: linkchecker, linkchecker.1 * The encoding can also be specified in the linkcheckerrc config file. Type: feature Changed: config/linkcheckerrc * All leading directories of a given output log file are created automatically now. Errors creating these directories or opening the log file for writing abort the checking and print a usage mesage. Type: feature Changed: linkchecker, linkcheck/logger/__init__.py * Coerce url names to unicode Type: feature Changed: linkcheck/checker/__init__.py * Accept unicode filenames for resolver config Type: feature Changed: linkcheck/dns/resolver.py * LinkChecker accepts now Unicode domain names and converts them according to RFC 3490 (http://www.faqs.org/rfcs/rfc3490.html). Type: feature Changed: linkcheck/dns/resolver.py, linkcheck/url.py * Exceptions in the log systems are no more caught. Type: feature Changed: linkcheck/ansicolor.py * Remember a tag in the link parser. Saves one HTML parse. Type: feature Changed: linkcheck/checker/urlbase.py, linkcheck/linkparse.py * Optimize link name parsing of img alt tags. Type: feature Changed: linkcheck/linkname.py * Remove all references to the old 'colored' output logger. Type: documentation Closes: SF bug #1062011 Changed: linkchecker.1 * Synchronized the linkchecker documentation and the man page. Type: documentation Closes: SF bug #1062034 Changed: linkchecker, linkchecker.1 * Make --quiet an alias for -o none. Type: bugfix Closes: SF bug #1063144 Changed: linkchecker, linkcheck/configuration.py, linkcheck/checker/consumer.py * Re-norm a changed file:// base url, avoiding a spurious warning. Type: bugfix Changed: linkcheck/checker/fileurl.py * Wrong case of file links on Windows platforms now issue a warning. Type: feature Closes: SF bug #1062007 Changed: linkcheck/checker/fileurl.py * Updated the french translation. Thanks to Yann Verley. Type: feature Changed: po/fr.po 1.13.5 "Die Musterknaben" (released 22.9.2004) * Use xgettext with Python support for .pot file creation, adjusted developer documentation. Type: feature Changed: doc/install.txt, po/Makefile, MANIFEST.in Removed: po/pygettext.py, po/msgfmt.py * Use plural gettext form for log messages. Type: feature Changed: linkcheck/logger/{text,html}.py * Check if FTP file really exists instead of only the parent dir. Type: bugfix Changed: linkcheck/checker/ftpurl.py * Document the different logger output types. Type: documentation Changed: linkchecker, linkchecker.1 * Recursion into FTP directories and parseable files has been implemented. Type: feature Changed: linkcheck/checker/ftpurl.py 1.13.4 "Shaun of the dead" (released 17.9.2004) * Catch HTTP cookie errors and add a warning. Type: bugfix Changed: linkcheck/checker/httpurl.py * fix up response page object in robots.txt parser for the upcoming Python 2.4 release Type: bugfix Changed: linkcheck/robotparser2.py * remove cached urls from progress queue, fixing endless wait for checking to finish Type: bugfix Changed: linkcheck/checker/consumer.py * updated and synchronized documentation of the man page (linkchecker.1) and the linkchecker --help output. Type: documentation Changed: linkchecker, linkchecker.1 1.13.3 "Fight Club" (released 10.9.2004) * Prevent collapsing of relative parent dir paths. This fixes false positives on URLs of the form "../../foo". Closes: SF bug #1025459 Changed: linkcheck/url.py, linkcheck/tests/test_url.py 1.13.2 "Zatoichi" (released 8.9.2004) * Fix permissions of data files on install to be world readable. Type: bugfix Closes: SF bug #1022132 Changed: setup.py * Fixed the SQL logger when encountering empty URLs. Type: bugfix Closes: SF bug #1022156 Changed: linkcheck/logger/sql.py * Added notes about access rules for CGI scripts Type: documentation Changed: doc/install.txt * Updated french translation. Thanks, Yann Verley! Type: feature Changed: po/fr.po * initialize i18n at program start Type: bugfix Changed: linkchecker, linkcheck/lc_cgi.py * Make initialization function for i18n, and allow LOCPATH to override the locale directory. Type: feature Changed: linkcheck/__init__.py * Removed debug print statement when issueing linkchecker --help. Type: bugfix Changed: linkchecker * Reset to default ANSI color scheme, we don't know what background color the terminal has. Type: bugfix Closes: SF bug #1022158 Changed: linkcheck/configuration.py * Reinit the logger object when config files change values. Type: bugfix Changed: linkcheck/configuration.py * Only import ifconfig routines on POSIX systems. Type: bugfix Closes: SF bug #1024607 Changed: linkcheck/dns/resolver.py 1.13.1 "Old men in new cars" (released 3.9.2004) * Fixed RPM generation by adding the generated config file to the installed files list. Type: bugfix Changed: setup.py * Mention to remove old versions when upgrading in the documentation. Type: documentation Changed: doc/upgrading.txt, doc/install.txt * Fix typo in redirection cache handling. Type: bugfix Changed: linkcheck/checker/cache.py * The -F file output must honor verbose/quiet configuration. Type: bugfix Changed: linkcheck/checker/consumer.py * Generate all translation files under windows systems. Type: bugfix Changed: po/Makefile * Added windows binary installer script and configuration. Type: feature Changed: setup.py, setup.cfg, doc/install.txt Added: install-linkchecker.py * Do not raise an error when user and/or password of ftp URLs is not specified. Type: bugfix Changed: linkcheck/checker/ftpurl.py * honor anchor part of cache url key, handle the recursion check with an extra cache key Type: bugfix Changed: linkcheck/checker/{urlbase,cache,fileurl}.py * Support URL lists in text files with one URL per line. Empty lines or comment lines starting with '#' are ignored. Type: feature Changed: linkcheck/checker/fileurl.py * Added new option --extern-strict to specify strict extern url patterns. Type: feature Changed: linkchecker * Strip quotes from parsed CSS urls. Type: bugfix Changed: linkcheck/checker/urlbase.py 1.13.0 "The Butterfly Effect" (released 1.9.2004) * lots of internal code restructuring Type: code cleanup Changed: a lot * If checking revealed errors (or warnings with --warnings), the command line client exits with a non-zero exit status. Type: feature Closes: SF bug 1013191 Changed: linkchecker, linkcheck/checker/consumer.py * Specify the HTML doctype and charset in HTML output. Type: feature Closes: SF bug 1014283 Changed: linkcheck/logger/html.py * Fix endless loop on broken urls with non-empty anchor. Type: bugfix Changed: linkcheck/checker/httpurl.py * For news: or nntp: urls, entries in ~/.netrc are now ignored. You should give instead username/password info in the configuration file or on the command line. Type: bugfix Changed: linkcheck/checker/nntpurl.py * The HTML output shows now HTML and CSS validation links for the parent URL of invalid links. Type: feature Changed: linkcheck/logger/html.py * The status is now printed as default, it can be supressed with the new --no-status option. Type: feature Changed: linkchecker * The default recursion level is now infinite. Type: feature Changed: linkchecker * The 'outside of domain filter' is no more a warning but an informational message. A warning is inappropriate since the user is in full control over what links are extern or intern. Type: feature Closes: SF bug 1013206 Changed: linkcheck/urlbase.py * Renamed the --strict option to --extern-strict-all. Type: feature Changed: linkchecker * a new cache and queueing algorithm makes sure that no URL is checked twice. Type: feature Changed: linkcheck/checker/cache.py * the given user/password authententication is now also used to get robots.txt files. Type: feature Changed: linkcheck/robotparser2.py, linkcheck/checker/cache.py 1.12.3 "The Princess Bride" (released 27.5.2004) * fall back to GET on bad status line of a HEAD request Type: bugfix Changed: linkcheck/HttpUrlData.py * really fall back to GET with Zope servers; fixes infinite loop Type: bugfix Changed: linkcheck/HttpUrlData.py * better error msg on BadStatusLine error Type: feature Changed: linkcheck/UrlData.py * updated optcomplete to newest upstream Type: feature Changed: linkcheck/optcomplete.py * also quote query parts of urls Type: bugfix Changed: linkcheck/{HttpUrlData, url}.py * - preserve the order in which HTML attributes have been parsed - cope with trailing space in HTML comments Type: feature Changed: linkcheck/parser/{__init__.py,htmllex.l} Added: linkcheck/containers.py * rework anchor fallback Type: bugfix Changed: linkcheck/HttpUrlData.py * move contentAllowsRobot check to end of recursion check to avoid unnecessary GET request Type: bugfix Changed: linkcheck/UrlData.py 1.12.2 (release 4.4.2004) * use XmlUtils instead of xmlify for XML quoting Type: code cleanup Added: linkcheck/XmlUtils.py Changed: linkcheck/StringUtil.py, linkcheck/log/XMLLogger.py * don't require a value anymore with the --version option Type: bugfix Changed: linkchecker * before putting url data objects in the queue, check if they have correct syntax and are not already cached Type: optimization Changed: linkcheck/{UrlData,Config}.py * every once in a while, remove all already cached urls from the incoming queue. This action is reported when --status is given. Type: optimization Changed: linkcheck/Config.py * both changes above result in significant performance improvements when checking large websites, since a majority of the links tend to be navigation links to already-cached pages. Type: note * updated examples and put them before options in the man page for easier reading Type: documentation Changed: linkchecker, linkchecker.1 * added contact url and email to the HTTP User-Agent string, which gets us more accepted by some bot-blocking software; also see http://www.livejournal.com/bots/ Type: feature Changed: linkcheck/Config.py * only check robots.txt for http connections Type: bugfix Changed: linkcheck/{Http,}UrlData.py Closes: SF bug 928895 * updated regression tests Type: feature Changed: test/test_*.py, Makefile Added: test/run.sh * preserve the order in which HTML attributes have been parsed Type: feature Changed: linkcheck/parser/{__init__.py,htmllex.l} * handle and correct missing start quotes in HTML attributes Type: feature Changed: linkcheck/parser/htmllex.l * full parsing of .css files Type: feature Changed: linkcheck/{Http,}UrlData.py, linkcheck/linkparse.py * removed Gilman news draft Type: feature Removed: draft-gilman-news-url-00.txt 1.12.1 (release 21.2.2004) * raise IncompleteRead instead of ValueError on malformed chunked HTTP data Changed: linkcheck/httplib2.py * catch errors earlier in recursion check Changed: linkcheck/UrlData.py * quote url and parent url in log output Changed: linkcheck/log/*.py Added: linkcheck/url.py 1.12.0 (release 31.1.2004) * added LRU.setdefault function Changed: linkcheck/LRU.py Closes: SF bug 885916 * Added Mac OS X as supported platform (version 10.3 is known to work) Changed: README, INSTALL * HTML parser objects are now subclassable and collectable by the cyclic garbage collector Changed: linkcheck/parser/htmlparse.y * made some minor parser fixes for attribute scanning and JavaScript Changed: linkcheck/parser/htmllex.l * include the optcomplete module for bash autocompletion Added: linkcheck/optcomplete.py, linkcheck-completion Changed: MANIFEST.in, setup.py * print out nicer error message for unknown host names Changed: linkcheck/UrlData.py * added new logger type "none" printing out nothing which is handy for cron scripts. Changed: linkchecker, linkcheck/Config.py, linkcheck/log/__init__.py Added: linkcheck/log/NoneLogger.py * the -F file output option disables console output now Changed: linkchecker * added an example cron script Added: linkcheck-cron.sh Changed: MANIFEST.in, setup.py * only warn about missing anchor support servers when the url has actually an anchor Changed: linkcheck/HttpUrlData.py * always fall back to HTTP GET request when HEAD gave an error to cope with servers not supporting HEAD requests Changed: linkcheck/HttpUrlData.py, FAQ 1.10.3 (release 10.1.2004) * use the optparser module for command line parsing Changed: linkchecker, po/*.po * use Set() instead of hashmap Changed: linkcheck/Config.py * fix mime-type checking to allow parsing of .css stylesheets Changed: linkcheck/HttpUrlData.py * honor HTML meta tags for robots, ie. Changed: linkcheck/UrlData.py, linkcheck/linkparse.py * much less aggressive thread acquiring, this fixes the 100% CPU usage from the previous version Changed: linkcheck/Threader.py 1.10.2 (release 3.1.2004) * fixed CGI safe_url pattern, it was too strict Changed: linkcheck/lc_cgi.py * replace backticks with repr() or %r Changed: all .py files containing backticks, and po/*.po * make windows DNS nameserver parsing more robust Changed: linkcheck/DNS/Base.py Closes: SF bugs 863227,864383 * only cache used data, not the whole url object Changed: linkcheck/{Http,}UrlData.py * limit cached data Changed: linkcheck/{UrlData,Config}.py Added: linkcheck/LRU.py Closes: SF bug 864516 * use dummy_threading module and get rid of the _NoThreads functions Changed: linkchecker, linkcheck/{Config,Threader}.py, test/test_*.py * set default connection timeout to 60 seconds Changed: linkcheck/__init__.py * new option --status print regular messages about number of checked urls and urls still to check Changed: linkchecker, linkcheck/{__init__,Config}.py 1.10.1 (release 19.12.2003) * added Mandrake .spec file from Chris Green Added: linkchecker.spec Changed: MANIFEST.in * print last-modified date for http and https links in infos Changed: linkcheck/HttpUrlData.py * add detailed installation instructions for Windows Changed: INSTALL Closes: SF bug 857748 * updated the DNS nameserver config parse routines Changed: linkcheck/DNS/Base.py Added: linkcheck/DNS/winreg.py Removed: linkcheck/DNS/win32dns.py * fix https support test Changed: linkcheck/HttpUrlData.py 1.10.0 (released 7.12.2003) * catch httplib errors in robotparser Changed: linkcheck/robotparser2.py Closes: SF bug 836864 * - infinite recursion option with negative value works now - initialize self.urlparts to avoid crash when reading cached http urls - with --strict option do not add any automatic filters if the user gave his own on the command line Changed: linkcheck/UrlData.py 1.9.5 (released 31.10.2003) * Add Zope to servers with broken HEAD support, adjusted the FAQ Changed: linkcheck/HttpUrlData.py, FAQ Closes: SF bug 833419 * Disable psyco usage, it is causing infinite loops (this is a known issue with psyco); and it is disabling ctrl-c interrupts (this is also a known issue in psyco) Changed: linkchecker * use internal debug logger Changed: linkcheck/robotparser2.py * do not hardcode Accept-Encoding header in HTTP request Added: linkcheck/httplib2.py Changed: linkcheck/robotparser2.py 1.9.4 (released 22.10.2003) * parse CSS stylesheet files and check included urls, for example background images Changed: linkcheck/{File,Http,Ftp,}UrlData.py, linkcheck/linkparser.py * try to use psyco for the commandline linkchecker script Changed: linkchecker * when decompression of compressed HTML pages fails, assume the page is not compressed Changed: linkcheck/{robotparser2,HttpUrlData}.py 1.9.3 (released 16.10.2003) * re-added an updated robot parser which uses urllib2 and can decode compressed transfer encodings. Added: linkcheck/robotparser2.py * more restrictive url validity checking when running in CGI mode Changed: linkcheck/lc_cgi.py * accept more Windows path specifications, like file://C:\Dokume~1\test.html Changed: linkcheck/FileUrlData.py 1.9.2 * parser fixes: - do not #include , fixes build on some FreeBSD, Windows and Solaris/SunOS platforms - ignore first leading invalid backslash in a=\"b\" attributes Changed: linkcheck/parser/htmllex.{l,c} * add full script path to linkchecker on windows systems Changed: linkchecker.bat * fix generation of Linkchecker_Readme.txt under windows systems Changed: setup.py 1.9.1 * add documentation how to change the default C compiler Changed: INSTALL * fixed blacklist logging Changed: linkcheck/log/BlacklistLogger.py * removed unused imports Changed: linkcheck/*.py * parser fixes: - fixed parsing of end tags with trailing garbage - fixed parsing of script single comment lines Changed: linkcheck/parser/htmllex.l 1.9.0 * Require Python 2.3 - removed timeoutsocket.py and robotparser.py, using upstream - use True/False for boolean values - use csv module - use new-style classes Closes: SF bug 784977 Changed: a lot * update po makefiles and tools Changed po/* * start CGI output immediately Changed: lc.cgi, lc.fcgi, lc.sz_fcgi, linkcheck/lc_cgi.py Closes: SF bug 784331 1.8.22 * allow colons in HTML attribute names, used for namespaces Changed: linkcheck/parser/htmllex.l * fix match of intern patterns with --denyallow enabled Changed: linkcheck/UrlData.py * s/intern/internal/ and s/extern/external/ in the documentation Changed: linkchecker, linkchecker.1, FAQ * rename column "column" to "col" in SQL output, since "column" is a reserved keyword. Thanks Garvin Hicking for the hint. Changed: linkcheck/log/SQLLogger.py, create.sql * handle HTTP redirects to a non-http url Changed: linkcheck/{Http,}UrlData.py Closes: SF bug 784372 1.8.21 * detect recursive redirections; the maximum of five redirections is still there though * after every HTTP 301 or 302 redirection, check the URL cache again Closes: SF bug 776851 * put all HTTP 301 redirection answers also in the url cache as aliases of the original url. this could mess up some redirection warnings (ie warn about redirection when there is none), but it is more network efficient. 1.8.20 * fix setting of domain in set_intern_url Changed: linkcheck/UrlData.py * - parse JS strings and comments - accept "". Changed files: linkcheck/UrlData.py, linkchecker 1.8.17 * fix parsing of missing end tag in "" Changed files: linkcheck/parser/htmllex.l * fix entity resolving in parsed html links Closes: SF bug #749543 Changed files: linkcheck/StringUtil.py 1.8.16 * also look at id attributes on anchor check (Closes SF Bug #741131) Changed files: linkcheck/{linkparser,UrlData}.py * minor parser cleanups Changed files: linkcheck/parser/* 1.8.15 * Fix compile errors with C variable declarations in HTML parser. Thanks to Fazal Majid Changed files: linkcheck/parser/htmlparse.[yc] 1.8.14 * fix old bug in redirects not using the full url. This resulted in errors like (-2, "Name or service not known") Changed files: linkcheck/HttpUrlData.py Closes: SF Bug #729007 * only remove anchors on IIS servers (other servers are doing quite well with anchors... can you spell A-p-a-c-h-e ?) Changed files: linkcheck/{HttpUrlData, UrlData}.py * Parser changes: - correctly propagate and display parsing errors - really cope with missing ">" end tags Changed files: linkcheck/parser/html{lex.l, parse.y}, linkcheck/linkparse.py, linkcheck/UrlData.py * quote urls before a request Changed files: linkcheck/HttpUrlData.py 1.8.13 * fix typo in manpage Changed files: linkchecker.1 * remove anchor from HEAD and GET requests Changed files: linkcheck/{HttpUrlData, UrlData}.py 1.8.12 * convert urlparts to list also on redirect Changed files: linkcheck/HttpUrlData.py 1.8.11 * catch httplib.error exceptions Changed files: linkcheck/HttpUrlData.py * override interactive password question in robotparser.py Changed files: linkcheck/robotparser.py * switch to urllib2.py as default url connect. Changed files: linkcheck/UrlData.py * recompile html parser with flex 2.5.31 Changed files: linkcheck/parser/{htmllex.c,Makefile} 1.8.10 * new option --no-anchor-caching Changed files: linkchecker, linkcheck/{Config.py, UrlData.py}, FAQ * quote empty attribute arguments Changed files: linkcheck/parser/htmllex.[lc] 1.8.9 * recompile with bison 1.875a Changed files: linkcheck/parser/htmlparse.[ch] * remove stpcpy declaration, fixes compile error on RedHat 7.x Changed files: linkcheck/parser/htmlsax.h * clarify keyboard interrupt warning to wait for active connections to finish Changed files: linkcheck/__init__.py * resolve &#XXX; number entity references Changed files: linkcheck/{StringUtil.py,linkname.py} 1.8.8 * All amazon servers block HEAD requests with timeouts. Use GET as a workaround, but issue a warning. Changed files: linkcheck/HttpUrlData.py * restrict CGI access to localhost per default Changed files: lc.cgi, lc.fcgi, lc.sz_fcgi, linkcheck/lc_cgi.py 1.8.7 * #define YY_NO_UNISTD_H on Windows systems, fixes build error with Visual Studio compiler Changed files: setup.py * use python2.2 headers for parser compile, not 2.1. Changed files: linkcheck/parser/Makefile 1.8.6 * include a fixed robotparser.py (from Python 2.2 CVS maint branch) 1.8.5 * fix config.warn to warn Changed files: linkcheck/__init.py * parser changes: o recognise "" HTML comments (seen at Eonline) o recognise "" HTML comments (seen at www.nba.com) o rebuild with flex 2.5.27 Changed files: linkcheck/parser/htmllex.[lc] * added another url exclusion example to the FAQ numerate questions and answers Changed files: FAQ * fix linkchecker exceptions Changed files: linkcheck/{Ftp,Mailto,Nntp,Telnet,}UrlData.py, linkcheck/__init__.py 1.8.4 * Improve error message for failing htmlsax module import Changed files: linkcheck/parser/htmllib.py * Regenerate parser with new bison 1.875 Changed files: linkcheck/parser/htmlparser.c * Some CVS files were not the same as their local counterpart. Something went wrong. Anyway, I re-committed them. Changed files: a lot .py files 1.8.3 * add missing imports for StringUtil in log classes, defer i18n of log field names (used for CGI scripts) Changed files: linkcheck/log/*.py * fixed wrong debug level comparison from > to >= Changed files: linkcheck/Config.py * JavaScript checks in the CGI scripts Changed files: lconline/lc_cgi.html.* Added files: lconline/check.js * Updated documentation with a link restriction example Changed files: linkchecker, linkchecker.1, FAQ * Updated po/pygettext.py to version 1.5, cleaned up some gettext usages. * updated i18n Added files: linkcheck/i18n.py Changed files: all .py files using i18n * Recognise "= 2.2.1, remove httplib. Changed files: setup.py, INSTALL, linkchecker * Add again python-dns, the Debian package maintainer is unresponsive Added files: linkcheck/DNS/*.py Changed files: INSTALL, setup.py * You must now use named constants for ANSII color codes Changed files: linkcheckerrc, linkcheck/log/ColoredLogger.py * Release RedHat 8.0 rpm packages. Changed files: setup.py, MANIFEST.in * remove --robots-txt from manpage, fix HTZP->HTTP typo Changed files: linkchecker.1 1.7.1 * Fix memory leak in HTML parser flushing error path Changed files: htmlparse.y * add custom line and column tracking in parser Changed files: htmllex.l, htmlparse.y, htmlsax.h, htmllib.py * Use column tracking in urldata classes Changed files: UrlData.py, FileUrlData,py, FtpUrlData.py, HostCheckingUrlData.py * Use column tracking in logger classes Changed files: StandardLogger.py CVSLogger.py, ColoredLogger.py, HtmlLogger.py, SqlLogger.py 1.7.0 * Added new HTML parser written in C as a Python extension module. It is faster and it is more fault tolerant. Of course, this means I cannot provide .exe installers any more since the distutils dont provide cross-compilation. 1.6.7 * Removed check for tags codebase attribute, but honor it when checking applet links * Handle tags archive attribute as a comma separated list Closes: SF bug #636802 * Fix a nasty bug in tag searching, which ignored tags with more than one link attribute in it. * Fix concatenation with relative base urls by first joining the parent url. * New commandline option --profile to write profile data. * Add httplib.py from Python CVS 2.1 maintenance branch, which has the skip_host keyword argument I am using now. 1.6.6 * Use the new HTTPConnection/HTTPResponse interface of httplib Closes: SF bug #634679 Changed files: linkcheck/HTTPUrlData.py, linkcheck/HTTPSUrlData.py * Updated the ftp online test Changed files: test/output/test_ftp 1.6.5 * Catch the maximum recursion limit error while parsing links and print an error message instead of bailing out. Changed files: linkcheck/UrlData.py * Fixed Ctrl-C only interrupting one single thread, not the whole program. Changed files: linkcheck/UrlData.py, linkcheck/__init__.py * HTML syntax cleanup and relative cgi form url for the cgi scripts Changed files: lconline/*.html 1.6.4 * Support for ftp proxies Changed files: linkcheck/FtpUrlData.py, linkcheck/HttpUrlData.py Added files: linkcheck/ProxyUrlData.py * Updated german translation 1.6.3: * Generate md5sum checksums for distributed files Changed files: Makefile * use "startswith" string method instead of a regex Changed files: linkchecker, linkcheck/UrlData.py * Add a note about supported languages, updated the documentation. Changed files: README, linkchecker, FAQ * Remove --robots-txt option from documentation, it is per default enabled and you cannot disable it from the command line. Changed files: linkchecker, po/*.po * fix --extern argument creation Changed files: linkchecker, linkcheck/UrlData.py * Print help if PyDNS module is not installed Changed files: linkcheck/UrlData.py * Print information if a proxy was used. Changed files: linkcheck/HttpUrlData.py * Updated german documentation Changed files: po/de.po * Oops, an FTP proxy is not used. Will make it in the next release. Changed files: linkcheck/FtpUrlData.py * Default socket timeout is now 30 seconds (10 was too short) 1.6.2: * Warn about unknown Content-Encodings. Dont parse HTML in this case. * Support deflate content encoding (snatched from Debians reportbug) * Add appropriate Accept-Encoding header to HTTP request. * Updated german translations 1.6.1: * FileUrlData.py: remove searching for links in text files, this is error prone. Just handle *.html and Opera Bookmarks. * Make separate ChangeLog from debian/changelog. For previous changes, see debian/changelog. * Default socket timeout is now 10 seconds * updated linkcheck/timeoutsocket.py to newest version * updated README and INSTALL * s/User-agent/User-Agent/, use same case as other browsers linkchecker-10.5.0/doc/development.md000066400000000000000000000045161466565367000175200ustar00rootroot00000000000000Developing LinkChecker ====================== The following steps describe how to work with the LinkChecker source which can be found on [GitHub](https://github.com/linkchecker/linkchecker/) where development is managed. This is a technical document, if you are looking for ways to participate in the community, you should rather look into [contributing](../CONTRIBUTING.rst). Requirements ------------ hatchling and hatch-vcs are used to create the application metadata and build distribution packages. These requirements are in addition to the dependencies covered in the [installation instructions](install.txt). Developers may wish to install hatch or tox to manage running tests. To run the copy of linkchecker in the local repository first create the metadata in linkcheck/_release.py: hatchling build -t sdist --hooks-only Then linkchecker can be run with: python -m linkcheck Workflows using GitHub Actions are used to check every PR, each commit and regularly the repository HEAD. Developers are able to perform these checks locally, using `flake8` for code style, and run the test suite with `tox` or `hatch -e test run tests` that are both configured to use pytest. `hatchling build` creates distributions packages. Source layout ------------- Important files and directories for developers to be aware of: .flake8 .gitignore .yamllint Dockerfile pyproject.toml pytest.ini robots.txt - test file tox.ini .github/ - GitHub automation cgi-bin/ - WSGI frontend doc/ - documentation including source for web site and man pages linkcheck/ - core code and CLI frontend po/ - application translations scripts/ - automated IANA schemes updater, analysis tools tests/ tools/ - build scripts Release process --------------- 1. check whether updated man pages and translations need committing (`make locale; make -C doc locale; make -C doc man`) if so create a pull request using the GitHub workflow: "Create a branch with updated man pages and application translations" 2. run `scripts/update_iana_uri_schemes.sh` and commit any changes 3. edit `changelog.txt` and `upgrading.txt` 4. confirm tests have passed 5. submit a pull request 6. create release (vX.Y.Z) on GitHub 7. check release has been created on PyPI linkchecker-10.5.0/doc/documentation.md000066400000000000000000000025661466565367000200520ustar00rootroot00000000000000LinkChecker Documentation ========================= LinkChecker is documented with man pages and HTML that is used for the project web site. Both are generated using Sphinx, with Makefiles provided to simplify the process. Sources are found in doc/src. Stand-alone .rst files from doc/ are also included. In addition to Sphinx the dependencies for building the documentation are: graphviz sphinx_epytext sphinx_rtd_theme sphinx_sitemap Configuration ------------- Before building either man pages or HTML, generate ``linkcheck/_release.py`` containing copyright, author and version with: ``hatchling build -t sdist --hooks-only`` Man Pages --------- Source files are in doc/src/man. The pages can be built with: ``linkchecker/doc $ make man`` The files are saved in doc/man. See translations.md for information about creating localised man pages. Published man pages are included in the LinkChecker repository. HTML ---- Build the HTML files with: ``linkchecker/doc $ make html`` The files are saved in doc/html. Publishing the Web Site ----------------------- The Web Site is hosted by GitHub Pages from the gh-pages branch. A ``.nojekyll`` file is present to ensure folders beginning with an underscore are published. When updates to LinkChecker are pushed, the web site is built and published automatically by a GitHub action ``.github/workflows/publish-pages.yml``. linkchecker-10.5.0/doc/examples/000077500000000000000000000000001466565367000164645ustar00rootroot00000000000000linkchecker-10.5.0/doc/examples/check_failures.sh000077500000000000000000000021621466565367000217730ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2004-2009 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. # # This script is intended to be run daily from cron. It complains when # URLs fail for at least a number of script runs. LOGFILE="$XDG_DATA_HOME/linkchecker/failures" linkchecker -Ffailures "$@" # this awk script complains if urls fail for at least two script runs [ -r $LOGFILE ] && awk '/^[[:digit:]]+/ {if ($1 > 1) printf "URL %s failed for %d days.", $2, $1; }' $LOGFILE linkchecker-10.5.0/doc/examples/check_for_x_errors.sh000077500000000000000000000020021466565367000226630ustar00rootroot00000000000000#!/bin/sh # This script is in the public domain. # Author of this script is Daniel Webb # Modified by Bastian Kleineidam: # - added hash-bang first line # - documentation # - removed second function, run them commands as-is # - use $TMPDIR if it exists # # Check web site links once per day, report only when the check had more # than X errors. # Return 0 # arguments: # $1 - web site URL # $2 - notification email # $3 - threshold number of errors # die() { echo "$0: $*"; exit 1; } logfile=${TMPDIR-/tmp}/linkchecker.log [ -z "$1" -o -z "$2" -o -z "$3" ] && die "check_web_links requires three arguments" do_check=false if [ ! -f $logfile ]; then do_check=true else # Has it been at least a day since last check? find $logfile -mtime +1 | grep link && do_check=true fi if [ $do_check = true ]; then linkchecker $1 >$logfile 2>/dev/null errors=$(grep Error: $logfile | wc -l) if [ $errors -gt $3 ]; then cat $logfile | mail -s "linkchecker: more than $3 errors" $2 fi fi return 0 linkchecker-10.5.0/doc/examples/check_urls.sh000077500000000000000000000031041466565367000211430ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2004-2009 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. # # Script suitable for cron job URL checking # Usage: # check_urls.sh [--cron] [linkchecker options] [urls...] # # And with crontab -e you add for example the following entry: # # # check my site each night # 10 4 * * * $HOME/bin/check_urls.sh --cron http://mysite.com/ # # To only get a mail when errors are encountered, you have to disable # the intro and outro output in a config file $XDG_CONFIG_HOME/linkchecker/cron: # # [text] # parts=realurl,result,extern,base,name,parenturl,info,warning,url # if which linkchecker > /dev/null; then LC=linkchecker else echo "linkchecker binary not found" exit 1 fi LCOPTS="-f$XDG_CONFIG_HOME/linkchecker/cron" if [ "$1" = "--cron" ]; then shift LCOPTS="$LCOPTS --no-status" D=/dev/null else D=/dev/stdout fi echo "Begin checking..." > $D $LC $LCOPTS "$@" linkchecker-10.5.0/doc/examples/filter_xml_output.py000066400000000000000000000030651466565367000226270ustar00rootroot00000000000000#!/usr/bin/python # Copyright (C) 2011 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Example to filter XML output. Call with XML output filename as first argument. Prints filtered result on standard output. """ import sys from xml.etree.ElementTree import parse def main(args): filename = args[0] with open(filename) as fd: tree = parse(fd) filter_tree(tree) tree.write(sys.stdout, encoding="utf-8") def filter_tree(tree): """Filter all 401 errors.""" to_remove = [] for elem in tree.findall("urldata"): valid = elem.find("valid") if ( valid is not None and valid.text == "0" and valid.attrib.get("result", "").startswith("401") ): to_remove.append(elem) root = tree.getroot() for elem in to_remove: root.remove(elem) if __name__ == "__main__": main(sys.argv[1:]) linkchecker-10.5.0/doc/examples/linkcheckerrc_loginurl000066400000000000000000000005211466565367000231270ustar00rootroot00000000000000# example configuration file demonstrating the login URL feature [authentication] entry= # Note that the password has been left out. # It will be entered at the commandline. ^https?://sourceforge\.net/account/login\.php calvin loginurl=https://sourceforge.net/account/login.php loginuserfield=form_loginname loginpasswordfield=form_pw linkchecker-10.5.0/doc/examples/windows.bat000066400000000000000000000004051466565367000206450ustar00rootroot00000000000000@echo off :: Do replace the for loop with setting SCRIPTSDIR to the literal path for /f "delims=" %%i in ('python -c "import site; print(site.getusersitepackages().replace('site-packages', 'Scripts'))"') do set SCRIPTSDIR=%%i python %SCRIPTSDIR%\linkchecker %* linkchecker-10.5.0/doc/i18n/000077500000000000000000000000001466565367000154255ustar00rootroot00000000000000linkchecker-10.5.0/doc/i18n/gettext/000077500000000000000000000000001466565367000171115ustar00rootroot00000000000000linkchecker-10.5.0/doc/i18n/gettext/index.pot000066400000000000000000000075651466565367000207610ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) 2000-2016 Bastian Kleineidam, 2010-2024 LinkChecker Authors # This file is distributed under the same license as the LinkChecker package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: LinkChecker 10.4.0.post49+g7cf5037e\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-08-27 18:46+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../src/index.rst:6 msgid "Check websites for broken links" msgstr "" #: ../../src/index.rst:9 msgid "Introduction" msgstr "" #: ../../src/index.rst:10 msgid "LinkChecker is a free, `GPL `_ licensed website validator. LinkChecker checks links in web documents or full websites. It runs on Python 3 systems, requiring Python 3.9 or later." msgstr "" #: ../../src/index.rst:15 msgid "Visit the project on `GitHub `_." msgstr "" #: ../../src/index.rst:18 msgid "Installation" msgstr "" #: ../../src/index.rst:24 msgid "The version in the pip repository may be old, to find out how to get the latest code, plus platform-specific information and other advice see the :doc:`installation document `." msgstr "" #: ../../src/index.rst:29 msgid "Basic usage" msgstr "" #: ../../src/index.rst:30 msgid "To check a URL like *http://www.example.org/myhomepage/* it is enough to execute:" msgstr "" #: ../../src/index.rst:37 msgid "This check will validate recursively all pages starting with *http://www.example.org/myhomepage/*. Additionally, all external links pointing outside of *www.example.org* will be checked but not recursed into." msgstr "" #: ../../src/index.rst:42 msgid "Find out more from the manual pages :doc:`man/linkchecker` and :doc:`man/linkcheckerrc`." msgstr "" #: ../../src/index.rst:46 msgid "Features" msgstr "" #: ../../src/index.rst:48 msgid "recursive and multithreaded checking and site crawling" msgstr "" #: ../../src/index.rst:49 msgid "output in colored or normal text, HTML, SQL, CSV, XML or a sitemap graph in different formats" msgstr "" #: ../../src/index.rst:51 msgid "HTTP/1.1, HTTPS, FTP, mailto: and local file links support" msgstr "" #: ../../src/index.rst:52 msgid "restriction of link checking with regular expression filters for URLs" msgstr "" #: ../../src/index.rst:53 msgid "proxy support" msgstr "" #: ../../src/index.rst:54 msgid "username/password authorization for HTTP and FTP" msgstr "" #: ../../src/index.rst:55 msgid "honors robots.txt exclusion protocol" msgstr "" #: ../../src/index.rst:56 msgid "Cookie support" msgstr "" #: ../../src/index.rst:57 msgid "HTML5 support" msgstr "" #: ../../src/index.rst:58 msgid ":ref:`Plugin support ` allowing custom page checks" msgstr "" #: ../../src/index.rst:59 msgid "Different interfaces: command line and web interface" msgstr "" #: ../../src/index.rst:62 msgid "Screenshots" msgstr "" #: ../../src/index.rst:72 msgid "Commandline interface" msgstr "" #: ../../src/index.rst:73 msgid "WSGI web interface" msgstr "" #: ../../src/index.rst:76 msgid "Test suite status" msgstr "" #: ../../src/index.rst:77 msgid "Linkchecker has extensive unit tests to ensure code quality. `GitHub Actions `_ is used for continuous build and test integration." msgstr "" #: ../../src/index.rst:-1 msgid "Build Status" msgstr "" #: ../../src/index.rst:86 msgid "Icon" msgstr "" #: ../../src/index.rst:88 msgid "The project icon is categories/applications-development-web from `Oxygen icons `_ copyright KDE and licensed under the `GNU LGPL version 3 `_ or later." msgstr "" linkchecker-10.5.0/doc/i18n/gettext/man.pot000066400000000000000000001600111466565367000204070ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) 2000-2016 Bastian Kleineidam, 2010-2024 LinkChecker Authors # This file is distributed under the same license as the LinkChecker package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: LinkChecker 10.4.0.post49+g7cf5037e\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-08-27 18:46+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../src/man/linkchecker.rst:4 msgid "linkchecker" msgstr "" #: ../../src/man/linkchecker.rst:7 msgid "SYNOPSIS" msgstr "" #: ../../src/man/linkchecker.rst:9 msgid "**linkchecker** [*options*] [*file-or-url*]..." msgstr "" #: ../../src/man/linkchecker.rst:12 #: ../../src/man/linkcheckerrc.rst:7 msgid "DESCRIPTION" msgstr "" #: ../../src/man/linkchecker.rst:14 msgid "LinkChecker features" msgstr "" #: ../../src/man/linkchecker.rst:16 msgid "recursive and multithreaded checking" msgstr "" #: ../../src/man/linkchecker.rst:17 msgid "output in colored or normal text, HTML, SQL, CSV, XML or a sitemap graph in different formats" msgstr "" #: ../../src/man/linkchecker.rst:19 msgid "support for HTTP/1.1, HTTPS, FTP, mailto: and local file links" msgstr "" #: ../../src/man/linkchecker.rst:20 msgid "restriction of link checking with URL filters" msgstr "" #: ../../src/man/linkchecker.rst:21 msgid "proxy support" msgstr "" #: ../../src/man/linkchecker.rst:22 msgid "username/password authorization for HTTP and FTP" msgstr "" #: ../../src/man/linkchecker.rst:23 msgid "support for robots.txt exclusion protocol" msgstr "" #: ../../src/man/linkchecker.rst:24 msgid "support for Cookies" msgstr "" #: ../../src/man/linkchecker.rst:25 msgid "support for HTML5" msgstr "" #: ../../src/man/linkchecker.rst:26 msgid "Antivirus check" msgstr "" #: ../../src/man/linkchecker.rst:27 msgid "a command line and web interface" msgstr "" #: ../../src/man/linkchecker.rst:30 msgid "EXAMPLES" msgstr "" #: ../../src/man/linkchecker.rst:32 msgid "The most common use checks the given domain recursively:" msgstr "" #: ../../src/man/linkchecker.rst:38 msgid "Beware that this checks the whole site which can have thousands of URLs. Use the :option:`-r` option to restrict the recursion depth." msgstr "" #: ../../src/man/linkchecker.rst:41 msgid "Don't check URLs with **/secret** in its name. All other links are checked as usual:" msgstr "" #: ../../src/man/linkchecker.rst:48 msgid "Checking a local HTML file on Unix:" msgstr "" #: ../../src/man/linkchecker.rst:54 msgid "Checking a local HTML file on Windows:" msgstr "" #: ../../src/man/linkchecker.rst:60 msgid "You can skip the **http://** url part if the domain starts with **www.**:" msgstr "" #: ../../src/man/linkchecker.rst:67 msgid "You can skip the **ftp://** url part if the domain starts with **ftp.**:" msgstr "" #: ../../src/man/linkchecker.rst:73 msgid "Generate a sitemap graph and convert it with the graphviz dot utility:" msgstr "" #: ../../src/man/linkchecker.rst:80 msgid "OPTIONS" msgstr "" #: ../../src/man/linkchecker.rst:83 msgid "General options" msgstr "" #: ../../src/man/linkchecker.rst:87 msgid "Use FILENAME as configuration file. By default LinkChecker uses $XDG_CONFIG_HOME/linkchecker/linkcheckerrc." msgstr "" #: ../../src/man/linkchecker.rst:92 msgid "Help me! Print usage information for this program." msgstr "" #: ../../src/man/linkchecker.rst:96 msgid "Generate no more than the given number of threads. Default number of threads is 10. To disable threading specify a non-positive number." msgstr "" #: ../../src/man/linkchecker.rst:101 msgid "Print version and exit." msgstr "" #: ../../src/man/linkchecker.rst:105 msgid "Print available check plugins and exit." msgstr "" #: ../../src/man/linkchecker.rst:108 msgid "Output options" msgstr "" #: ../../src/man/linkchecker.rst:111 #: ../../src/man/linkcheckerrc.rst:187 msgid "URL checking results" msgstr "" #: ../../src/man/linkchecker.rst:115 msgid "Output to a file linkchecker-out.TYPE, $XDG_DATA_HOME/linkchecker/failures for the failures output type, or FILENAME if specified. The ENCODING specifies the output encoding, the default is that of your locale. Valid encodings are listed at https://docs.python.org/library/codecs.html#standard-encodings. The FILENAME and ENCODING parts of the none output type will be ignored, else if the file already exists, it will be overwritten. You can specify this option more than once. Valid file output TYPEs are text, html, sql, csv, gml, dot, xml, sitemap, none or failures. Default is no file output. The various output types are documented below. Note that you can suppress all console output with the option :option:`-o` *none*." msgstr "" #: ../../src/man/linkchecker.rst:131 msgid "Don't log warnings. Default is to log warnings." msgstr "" #: ../../src/man/linkchecker.rst:135 msgid "Specify the console output type as text, html, sql, csv, gml, dot, xml, sitemap, none or failures. Default type is text. The various output types are documented below. The ENCODING specifies the output encoding, the default is that of your locale. Valid encodings are listed at https://docs.python.org/library/codecs.html#standard-encodings." msgstr "" #: ../../src/man/linkchecker.rst:144 msgid "Log all checked URLs, overriding :option:`--no-warnings`. Default is to log only errors and warnings." msgstr "" #: ../../src/man/linkchecker.rst:148 #: ../../src/man/linkcheckerrc.rst:230 msgid "Progress updates" msgstr "" #: ../../src/man/linkchecker.rst:152 msgid "Do not print URL check status messages." msgstr "" #: ../../src/man/linkchecker.rst:155 #: ../../src/man/linkcheckerrc.rst:237 msgid "Application" msgstr "" #: ../../src/man/linkchecker.rst:159 msgid "Print debugging output for the given logger. Available debug loggers are cmdline, checking, cache, plugin and all. all is an alias for all available loggers. This option can be given multiple times to debug with more than one logger." msgstr "" #: ../../src/man/linkchecker.rst:165 #: ../../src/man/linkcheckerrc.rst:246 msgid "Quiet" msgstr "" #: ../../src/man/linkchecker.rst:169 msgid "Quiet operation, an alias for :option:`-o` *none* that also hides application information messages. This is only useful with :option:`-F`, else no results will be output." msgstr "" #: ../../src/man/linkchecker.rst:174 msgid "Checking options" msgstr "" #: ../../src/man/linkchecker.rst:178 msgid "Use initial cookie data read from a file. The cookie data format is explained below." msgstr "" #: ../../src/man/linkchecker.rst:183 msgid "Check external URLs." msgstr "" #: ../../src/man/linkchecker.rst:187 msgid "URLs matching the given regular expression will only be syntax checked. This option can be given multiple times. See section `REGULAR EXPRESSIONS`_ for more info." msgstr "" #: ../../src/man/linkchecker.rst:193 msgid "Check but do not recurse into URLs matching the given regular expression. This option can be given multiple times. See section `REGULAR EXPRESSIONS`_ for more info." msgstr "" #: ../../src/man/linkchecker.rst:200 msgid "Check URLs regardless of any robots.txt files." msgstr "" #: ../../src/man/linkchecker.rst:204 msgid "Read a password from console and use it for HTTP and FTP authorization. For FTP the default password is anonymous@. For HTTP there is no default password. See also :option:`-u`." msgstr "" #: ../../src/man/linkchecker.rst:210 msgid "Check recursively all links up to given depth. A negative depth will enable infinite recursion. Default depth is infinite." msgstr "" #: ../../src/man/linkchecker.rst:215 msgid "Set the timeout for connection attempts in seconds. The default timeout is 60 seconds." msgstr "" #: ../../src/man/linkchecker.rst:220 msgid "Try the given username for HTTP and FTP authorization. For FTP the default username is anonymous. For HTTP there is no default username. See also :option:`-p`." msgstr "" #: ../../src/man/linkchecker.rst:226 msgid "Specify the User-Agent string to send to the HTTP server, for example \"Mozilla/4.0\". The default is \"LinkChecker/X.Y\" where X.Y is the current version of LinkChecker." msgstr "" #: ../../src/man/linkchecker.rst:231 msgid "Input options" msgstr "" #: ../../src/man/linkchecker.rst:235 msgid "Read from stdin a list of white-space separated URLs to check." msgstr "" #: ../../src/man/linkchecker.rst:239 msgid "The location to start checking with. A file can be a simple list of URLs, one per line, if the first line is \"# LinkChecker URL list\"." msgstr "" #: ../../src/man/linkchecker.rst:244 msgid "CONFIGURATION FILES" msgstr "" #: ../../src/man/linkchecker.rst:246 msgid "Configuration files can specify all options above. They can also specify some options that cannot be set on the command line. See :manpage:`linkcheckerrc(5)` for more info." msgstr "" #: ../../src/man/linkchecker.rst:251 #: ../../src/man/linkcheckerrc.rst:255 msgid "OUTPUT TYPES" msgstr "" #: ../../src/man/linkchecker.rst:253 msgid "Note that by default only errors and warnings are logged. You should use the option :option:`--verbose` to get the complete URL list, especially when outputting a sitemap graph format." msgstr "" #: ../../src/man/linkchecker.rst:257 msgid "**text**" msgstr "" #: ../../src/man/linkchecker.rst:258 msgid "Standard text logger, logging URLs in keyword: argument fashion." msgstr "" #: ../../src/man/linkchecker.rst:261 msgid "**html**" msgstr "" #: ../../src/man/linkchecker.rst:260 msgid "Log URLs in keyword: argument fashion, formatted as HTML. Additionally has links to the referenced pages. Invalid URLs have HTML and CSS syntax check links appended." msgstr "" #: ../../src/man/linkchecker.rst:263 msgid "**csv**" msgstr "" #: ../../src/man/linkchecker.rst:264 msgid "Log check result in CSV format with one URL per line." msgstr "" #: ../../src/man/linkchecker.rst:266 msgid "**gml**" msgstr "" #: ../../src/man/linkchecker.rst:266 msgid "Log parent-child relations between linked URLs as a GML sitemap graph." msgstr "" #: ../../src/man/linkchecker.rst:269 msgid "**dot**" msgstr "" #: ../../src/man/linkchecker.rst:269 msgid "Log parent-child relations between linked URLs as a DOT sitemap graph." msgstr "" #: ../../src/man/linkchecker.rst:271 msgid "**gxml**" msgstr "" #: ../../src/man/linkchecker.rst:272 msgid "Log check result as a GraphXML sitemap graph." msgstr "" #: ../../src/man/linkchecker.rst:273 msgid "**xml**" msgstr "" #: ../../src/man/linkchecker.rst:274 msgid "Log check result as machine-readable XML." msgstr "" #: ../../src/man/linkchecker.rst:276 msgid "**sitemap**" msgstr "" #: ../../src/man/linkchecker.rst:276 msgid "Log check result as an XML sitemap whose protocol is documented at https://www.sitemaps.org/protocol.html." msgstr "" #: ../../src/man/linkchecker.rst:279 msgid "**sql**" msgstr "" #: ../../src/man/linkchecker.rst:279 msgid "Log check result as SQL script with INSERT commands. An example script to create the initial SQL table is included as create.sql." msgstr "" #: ../../src/man/linkchecker.rst:283 msgid "**failures**" msgstr "" #: ../../src/man/linkchecker.rst:282 msgid "Suitable for cron jobs. Logs the check result into a file **$XDG_DATA_HOME/linkchecker/failures** which only contains entries with invalid URLs and the number of times they have failed." msgstr "" #: ../../src/man/linkchecker.rst:286 msgid "**none**" msgstr "" #: ../../src/man/linkchecker.rst:286 msgid "Logs nothing. Suitable for debugging or checking the exit code." msgstr "" #: ../../src/man/linkchecker.rst:289 msgid "REGULAR EXPRESSIONS" msgstr "" #: ../../src/man/linkchecker.rst:291 msgid "LinkChecker accepts Python regular expressions. See https://docs.python.org/howto/regex.html for an introduction. An addition is that a leading exclamation mark negates the regular expression." msgstr "" #: ../../src/man/linkchecker.rst:297 msgid "COOKIE FILES" msgstr "" #: ../../src/man/linkchecker.rst:299 msgid "A cookie file contains standard HTTP header (RFC 2616) data with the following possible names:" msgstr "" #: ../../src/man/linkchecker.rst:302 msgid "**Host** (required)" msgstr "" #: ../../src/man/linkchecker.rst:303 msgid "Sets the domain the cookies are valid for." msgstr "" #: ../../src/man/linkchecker.rst:304 msgid "**Path** (optional)" msgstr "" #: ../../src/man/linkchecker.rst:305 msgid "Gives the path the cookies are value for; default path is **/**." msgstr "" #: ../../src/man/linkchecker.rst:307 msgid "**Set-cookie** (required)" msgstr "" #: ../../src/man/linkchecker.rst:307 msgid "Set cookie name/value. Can be given more than once." msgstr "" #: ../../src/man/linkchecker.rst:309 msgid "Multiple entries are separated by a blank line. The example below will send two cookies to all URLs starting with **http://example.com/hello/** and one to all URLs starting with **https://example.org/**:" msgstr "" #: ../../src/man/linkchecker.rst:327 msgid "PROXY SUPPORT" msgstr "" #: ../../src/man/linkchecker.rst:329 msgid "To use a proxy on Unix or Windows set the :envvar:`http_proxy` or :envvar:`https_proxy` environment variables to the proxy URL. The URL should be of the form **http://**\\ [*user*\\ **:**\\ *pass*\\ **@**]\\ *host*\\ [**:**\\ *port*]. LinkChecker also detects manual proxy settings of Internet Explorer under Windows systems. On a Mac use the Internet Config to select a proxy. You can also set a comma-separated domain list in the :envvar:`no_proxy` environment variable to ignore any proxy settings for these domains. The :envvar:`curl_ca_bundle` environment variable can be used to identify an alternative certificate bundle to be used with an HTTPS proxy." msgstr "" #: ../../src/man/linkchecker.rst:341 msgid "Setting a HTTP proxy on Unix for example looks like this:" msgstr "" #: ../../src/man/linkchecker.rst:347 msgid "Proxy authentication is also supported:" msgstr "" #: ../../src/man/linkchecker.rst:353 msgid "Setting a proxy on the Windows command prompt:" msgstr "" #: ../../src/man/linkchecker.rst:360 msgid "PERFORMED CHECKS" msgstr "" #: ../../src/man/linkchecker.rst:362 msgid "All URLs have to pass a preliminary syntax test. Minor quoting mistakes will issue a warning, all other invalid syntax issues are errors. After the syntax check passes, the URL is queued for connection checking. All connection check types are described below." msgstr "" #: ../../src/man/linkchecker.rst:373 msgid "HTTP links (**http:**, **https:**)" msgstr "" #: ../../src/man/linkchecker.rst:368 msgid "After connecting to the given HTTP server the given path or query is requested. All redirections are followed, and if user/password is given it will be used as authorization when necessary. All final HTTP status codes other than 2xx are errors." msgstr "" #: ../../src/man/linkchecker.rst:373 msgid "HTML page contents are checked for recursion." msgstr "" #: ../../src/man/linkchecker.rst:380 msgid "Local files (**file:**)" msgstr "" #: ../../src/man/linkchecker.rst:376 msgid "A regular, readable file that can be opened is valid. A readable directory is also valid. All other files, for example device files, unreadable or non-existing files are errors." msgstr "" #: ../../src/man/linkchecker.rst:380 msgid "HTML or other parseable file contents are checked for recursion." msgstr "" #: ../../src/man/linkchecker.rst:395 msgid "Mail links (**mailto:**)" msgstr "" #: ../../src/man/linkchecker.rst:383 msgid "A mailto: link eventually resolves to a list of email addresses. If one address fails, the whole list will fail. For each mail address we check the following things:" msgstr "" #: ../../src/man/linkchecker.rst:387 msgid "Check the address syntax, both the parts before and after the @ sign." msgstr "" #: ../../src/man/linkchecker.rst:389 msgid "Look up the MX DNS records. If we found no MX record, print an error." msgstr "" #: ../../src/man/linkchecker.rst:391 msgid "Check if one of the mail hosts accept an SMTP connection. Check hosts with higher priority first. If no host accepts SMTP, we print a warning." msgstr "" #: ../../src/man/linkchecker.rst:394 msgid "Try to verify the address with the VRFY command. If we got an answer, print the verified address as an info." msgstr "" #: ../../src/man/linkchecker.rst:404 msgid "FTP links (**ftp:**)" msgstr "" #: ../../src/man/linkchecker.rst:398 msgid "For FTP links we do:" msgstr "" #: ../../src/man/linkchecker.rst:400 msgid "connect to the specified host" msgstr "" #: ../../src/man/linkchecker.rst:401 msgid "try to login with the given user and password. The default user is **anonymous**, the default password is **anonymous@**." msgstr "" #: ../../src/man/linkchecker.rst:403 msgid "try to change to the given directory" msgstr "" #: ../../src/man/linkchecker.rst:404 msgid "list the file with the NLST command" msgstr "" #: ../../src/man/linkchecker.rst:413 msgid "Unsupported links (**javascript:**, etc.)" msgstr "" #: ../../src/man/linkchecker.rst:407 msgid "An unsupported link will only print a warning. No further checking will be made." msgstr "" #: ../../src/man/linkchecker.rst:410 msgid "The complete list of recognized, but unsupported links can be found in the `linkcheck/checker/unknownurl.py `__ source file. The most prominent of them should be JavaScript links." msgstr "" #: ../../src/man/linkchecker.rst:416 msgid "SITEMAPS" msgstr "" #: ../../src/man/linkchecker.rst:418 msgid "Sitemaps are parsed for links to check and can be detected either from a sitemap entry in a robots.txt, or when passed as a :option:`FILE-OR-URL` argument in which case detection requires the urlset/sitemapindex tag to be within the first 70 characters of the sitemap. Compressed sitemap files are not supported." msgstr "" #: ../../src/man/linkchecker.rst:425 #: ../../src/man/linkcheckerrc.rst:490 msgid "PLUGINS" msgstr "" #: ../../src/man/linkchecker.rst:427 msgid "There are two plugin types: connection and content plugins. Connection plugins are run after a successful connection to the URL host. Content plugins are run if the URL type has content (mailto: URLs have no content for example) and if the check is not forbidden (ie. by HTTP robots.txt). Use the option :option:`--list-plugins` for a list of plugins and their documentation. All plugins are enabled via the :manpage:`linkcheckerrc(5)` configuration file." msgstr "" #: ../../src/man/linkchecker.rst:437 msgid "RECURSION" msgstr "" #: ../../src/man/linkchecker.rst:439 msgid "Before descending recursively into a URL, it has to fulfill several conditions. They are checked in this order:" msgstr "" #: ../../src/man/linkchecker.rst:442 msgid "A URL must be valid." msgstr "" #: ../../src/man/linkchecker.rst:443 msgid "A URL must be parseable. This currently includes HTML files, Opera bookmarks files, and directories. If a file type cannot be determined (for example it does not have a common HTML file extension, and the content does not look like HTML), it is assumed to be non-parseable." msgstr "" #: ../../src/man/linkchecker.rst:447 msgid "The URL content must be retrievable. This is usually the case except for example mailto: or unknown URL types." msgstr "" #: ../../src/man/linkchecker.rst:449 msgid "The maximum recursion level must not be exceeded. It is configured with the :option:`--recursion-level` option and is unlimited per default." msgstr "" #: ../../src/man/linkchecker.rst:451 msgid "It must not match the ignored URL list. This is controlled with the :option:`--ignore-url` option." msgstr "" #: ../../src/man/linkchecker.rst:453 msgid "The Robots Exclusion Protocol must allow links in the URL to be followed recursively. This is checked by searching for a \"nofollow\" directive in the HTML header data." msgstr "" #: ../../src/man/linkchecker.rst:457 msgid "Note that the directory recursion reads all files in that directory, not just a subset like **index.htm**." msgstr "" #: ../../src/man/linkchecker.rst:461 msgid "NOTES" msgstr "" #: ../../src/man/linkchecker.rst:463 msgid "URLs on the commandline starting with **ftp.** are treated like **ftp://ftp.**, URLs starting with **www.** are treated like **http://www.**. You can also give local files as arguments. If you have your system configured to automatically establish a connection to the internet (e.g. with diald), it will connect when checking links not pointing to your local host. Use the :option:`--ignore-url` option to prevent this." msgstr "" #: ../../src/man/linkchecker.rst:471 msgid "Javascript links are not supported." msgstr "" #: ../../src/man/linkchecker.rst:473 msgid "If your platform does not support threading, LinkChecker disables it automatically." msgstr "" #: ../../src/man/linkchecker.rst:476 msgid "You can supply multiple user/password pairs in a configuration file." msgstr "" #: ../../src/man/linkchecker.rst:479 msgid "ENVIRONMENT" msgstr "" #: ../../src/man/linkchecker.rst:483 msgid "specifies default HTTP proxy server" msgstr "" #: ../../src/man/linkchecker.rst:487 msgid "specifies default HTTPS proxy server" msgstr "" #: ../../src/man/linkchecker.rst:491 msgid "an alternative certificate bundle to be used with an HTTPS proxy" msgstr "" #: ../../src/man/linkchecker.rst:495 msgid "comma-separated list of domains to not contact over a proxy server" msgstr "" #: ../../src/man/linkchecker.rst:499 msgid "specify output language" msgstr "" #: ../../src/man/linkchecker.rst:502 msgid "RETURN VALUE" msgstr "" #: ../../src/man/linkchecker.rst:504 msgid "The return value is 2 when" msgstr "" #: ../../src/man/linkchecker.rst:506 msgid "a program error occurred." msgstr "" #: ../../src/man/linkchecker.rst:508 msgid "The return value is 1 when" msgstr "" #: ../../src/man/linkchecker.rst:510 msgid "invalid links were found or" msgstr "" #: ../../src/man/linkchecker.rst:511 msgid "link warnings were found and warnings are enabled" msgstr "" #: ../../src/man/linkchecker.rst:513 msgid "Else the return value is zero." msgstr "" #: ../../src/man/linkchecker.rst:516 msgid "LIMITATIONS" msgstr "" #: ../../src/man/linkchecker.rst:518 msgid "LinkChecker consumes memory for each queued URL to check. With thousands of queued URLs the amount of consumed memory can become quite large. This might slow down the program or even the whole system." msgstr "" #: ../../src/man/linkchecker.rst:523 msgid "FILES" msgstr "" #: ../../src/man/linkchecker.rst:525 msgid "**$XDG_CONFIG_HOME/linkchecker/linkcheckerrc** - default configuration file" msgstr "" #: ../../src/man/linkchecker.rst:527 msgid "**$XDG_DATA_HOME/linkchecker/failures** - default failures logger output filename" msgstr "" #: ../../src/man/linkchecker.rst:529 msgid "**linkchecker-out.**\\ *TYPE* - default logger file output name" msgstr "" #: ../../src/man/linkchecker.rst:532 #: ../../src/man/linkcheckerrc.rst:632 msgid "SEE ALSO" msgstr "" #: ../../src/man/linkchecker.rst:534 msgid ":manpage:`linkcheckerrc(5)`" msgstr "" #: ../../src/man/linkchecker.rst:536 msgid "https://docs.python.org/library/codecs.html#standard-encodings - valid output encodings" msgstr "" #: ../../src/man/linkchecker.rst:539 msgid "https://docs.python.org/howto/regex.html - regular expression documentation" msgstr "" #: ../../src/man/linkcheckerrc.rst:4 msgid "linkcheckerrc" msgstr "" #: ../../src/man/linkcheckerrc.rst:9 msgid "**linkcheckerrc** is the configuration file for LinkChecker. The file is written in an INI-style format. The default file location is **$XDG_CONFIG_HOME/linkchecker/linkcheckerrc** or else **~/.config/linkchecker/linkcheckerrc** on Unix, **%HOMEPATH%\\\\.config\\\\linkchecker\\\\linkcheckerrc** on Windows systems." msgstr "" #: ../../src/man/linkcheckerrc.rst:16 msgid "SETTINGS" msgstr "" #: ../../src/man/linkcheckerrc.rst:19 msgid "checking" msgstr "" #: ../../src/man/linkcheckerrc.rst:23 msgid "**cookiefile=**\\ *filename*" msgstr "" #: ../../src/man/linkcheckerrc.rst:22 msgid "Read a file with initial cookie data. The cookie data format is explained in :manpage:`linkchecker(1)`. Command line option: :option:`--cookiefile`" msgstr "" #: ../../src/man/linkcheckerrc.rst:27 msgid "**debugmemory=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:26 msgid "Write memory allocation statistics to a file on exit, requires :pypi:`meliae`. The default is not to write the file. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:34 msgid "**localwebroot=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:30 msgid "When checking absolute URLs inside local files, the given root directory is used as base URL. Note that the given directory must have URL syntax, so it must use a slash to join directories instead of a backslash. And the given directory must end with a slash. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:38 msgid "**recursionlevel=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:37 msgid "Check recursively all links up to given depth. A negative depth will enable infinite recursion. Default depth is infinite. Command line option: :option:`--recursion-level`" msgstr "" #: ../../src/man/linkcheckerrc.rst:42 msgid "**threads=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:41 msgid "Generate no more than the given number of threads. Default number of threads is 10. To disable threading specify a non-positive number. Command line option: :option:`--threads`" msgstr "" #: ../../src/man/linkcheckerrc.rst:46 msgid "**timeout=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:45 msgid "Set the timeout for connection attempts in seconds. The default timeout is 60 seconds. Command line option: :option:`--timeout`" msgstr "" #: ../../src/man/linkcheckerrc.rst:51 msgid "**aborttimeout=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:49 msgid "Time to wait for checks to finish after the user aborts the first time (with Ctrl-C or the abort button). The default abort timeout is 300 seconds. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:56 msgid "**useragent=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:54 msgid "Specify the User-Agent string to send to the HTTP server, for example \"Mozilla/4.0\". The default is \"LinkChecker/X.Y\" where X.Y is the current version of LinkChecker. Command line option: :option:`--user-agent`" msgstr "" #: ../../src/man/linkcheckerrc.rst:62 msgid "**sslverify=**\\ [**0**\\ \\|\\ **1**\\ \\|\\ *filename*]" msgstr "" #: ../../src/man/linkcheckerrc.rst:59 msgid "If set to zero disables SSL certificate checking. If set to one (the default) enables SSL certificate checking with the provided CA certificate file. If a filename is specified, it will be used as the certificate file. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:68 msgid "**maxrunseconds=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:65 msgid "Stop checking new URLs after the given number of seconds. Same as if the user stops (by hitting Ctrl-C) after the given number of seconds. The default is not to stop until all URLs are checked. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:74 msgid "**maxfilesizedownload=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:71 msgid "Files larger than NUMBER bytes will be ignored, without downloading anything if accessed over http and an accurate Content-Length header was returned. No more than this amount of a file will be downloaded. The default is 5242880 (5 MB). Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:78 msgid "**maxfilesizeparse=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:77 msgid "Files larger than NUMBER bytes will not be parsed for links. The default is 1048576 (1 MB). Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:83 msgid "**maxnumurls=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:81 msgid "Maximum number of URLs to check. New URLs will not be queued after the given number of URLs is checked. The default is to queue and check all URLs. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:91 msgid "**maxrequestspersecond=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:86 msgid "Limit the maximum number of HTTP requests per second to one host. The average number of requests per second is approximately one third of the maximum. Values less than 1 and at least 0.001 can be used. To use values greater than 10, the HTTP server must return a **LinkChecker** response header. The default is 10. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:96 msgid "**robotstxt=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:94 msgid "When using http, fetch robots.txt, and confirm whether each URL should be accessed before checking. The default is to use robots.txt files. Command line option: :option:`--no-robots`" msgstr "" #: ../../src/man/linkcheckerrc.rst:99 msgid "**allowedschemes=**\\ *NAME*\\ [**,**\\ *NAME*...]" msgstr "" #: ../../src/man/linkcheckerrc.rst:99 msgid "Allowed URL schemes as comma-separated list. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:104 msgid "**resultcachesize=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:102 msgid "Set the result cache size. The default is 100 000 URLs. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:107 msgid "filtering" msgstr "" #: ../../src/man/linkcheckerrc.rst:110 msgid "**ignore=**\\ *REGEX* (`MULTILINE`_)" msgstr "" #: ../../src/man/linkcheckerrc.rst:110 msgid "Only check syntax of URLs matching the given regular expressions. Command line option: :option:`--ignore-url`" msgstr "" #: ../../src/man/linkcheckerrc.rst:114 msgid "**ignorewarnings=**\\ *NAME*\\ [**,**\\ *NAME*...]" msgstr "" #: ../../src/man/linkcheckerrc.rst:113 msgid "Ignore the comma-separated list of warnings. See `WARNINGS`_ for the list of supported warnings. Messages are logged as information. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:130 msgid "**ignorewarningsforurls=**\\ *URL_REGEX* [*NAME_REGEX*] (`MULTILINE`_)" msgstr "" #: ../../src/man/linkcheckerrc.rst:117 msgid "Specify regular expressions to ignore warnings for matching URLs, one per line. On each line, you can specify a second regular expression, ensuring that only the warnings with names matching the second expression will be ignored for that URL. If the second expression is omitted, all warnings are ignored for that URL." msgstr "" #: ../../src/man/linkcheckerrc.rst:125 msgid "Default is to not ignore any warnings. See `WARNINGS`_ for the list of supported warnings. Messages are logged as information. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:130 msgid "Example:" msgstr "" #: ../../src/man/linkcheckerrc.rst:140 msgid "**internlinks=**\\ *REGEX*" msgstr "" #: ../../src/man/linkcheckerrc.rst:139 msgid "Regular expression to add more URLs recognized as internal links. Default is that URLs given on the command line are internal. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:144 msgid "**nofollow=**\\ *REGEX* (`MULTILINE`_)" msgstr "" #: ../../src/man/linkcheckerrc.rst:143 msgid "Check but do not recurse into URLs matching the given regular expressions. Command line option: :option:`--no-follow-url`" msgstr "" #: ../../src/man/linkcheckerrc.rst:148 msgid "**checkextern=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:147 msgid "Check external links. Default is to check internal links only. Command line option: :option:`--check-extern`" msgstr "" #: ../../src/man/linkcheckerrc.rst:151 msgid "authentication" msgstr "" #: ../../src/man/linkcheckerrc.rst:164 msgid "**entry=**\\ *REGEX* *USER* [*PASS*] (`MULTILINE`_)" msgstr "" #: ../../src/man/linkcheckerrc.rst:154 msgid "Provide individual username/password pairs for different links. In addition to a single login page specified with **loginurl** multiple FTP and HTTP (Basic Authentication) links are supported. Entries are a triple (URL regex, username, password) or a tuple (URL regex, username), where the entries are separated by whitespace. The password is optional and if missing it has to be entered at the commandline. If the regular expression matches the checked URL, the given username/password pair is used for authentication. The command line options :option:`-u` and :option:`-p` match every link and therefore override the entries given here. The first match wins. Command line option: :option:`-u`, :option:`-p`" msgstr "" #: ../../src/man/linkcheckerrc.rst:171 msgid "**loginurl=**\\ *URL*" msgstr "" #: ../../src/man/linkcheckerrc.rst:167 msgid "The URL of a login page to be visited before link checking. The page is expected to contain an HTML form to collect credentials and submit them to the address in its action attribute using an HTTP POST request. The name attributes of the input elements of the form and the values to be submitted need to be available (see **entry** for an explanation of username and password values)." msgstr "" #: ../../src/man/linkcheckerrc.rst:173 msgid "**loginuserfield=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:174 msgid "The name attribute of the username input element. Default: **login**." msgstr "" #: ../../src/man/linkcheckerrc.rst:175 msgid "**loginpasswordfield=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:176 msgid "The name attribute of the password input element. Default: **password**." msgstr "" #: ../../src/man/linkcheckerrc.rst:181 msgid "**loginextrafields=**\\ *NAME*\\ **:**\\ *VALUE* (`MULTILINE`_)" msgstr "" #: ../../src/man/linkcheckerrc.rst:178 msgid "Optionally the name attributes of any additional input elements and the values to populate them with. Note that these are submitted without checking whether matching input elements exist in the HTML form." msgstr "" #: ../../src/man/linkcheckerrc.rst:184 msgid "output" msgstr "" #: ../../src/man/linkcheckerrc.rst:195 msgid "**fileoutput=**\\ *TYPE*\\ [**,**\\ *TYPE*...]" msgstr "" #: ../../src/man/linkcheckerrc.rst:190 msgid "Output to a file **linkchecker-out.**\\ *TYPE*, or **$XDG_DATA_HOME/linkchecker/failures** for the **failures** output type. Valid file output types are **text**, **html**, **sql**, **csv**, **gml**, **dot**, **xml**, **none** or **failures**. Default is no file output. The various output types are documented below. Note that you can suppress all console output with **output=none**. Command line option: :option:`--file-output`" msgstr "" #: ../../src/man/linkcheckerrc.rst:203 msgid "**log=**\\ *TYPE*\\ [**/**\\ *ENCODING*]" msgstr "" #: ../../src/man/linkcheckerrc.rst:198 msgid "Specify the console output type as **text**, **html**, **sql**, **csv**, **gml**, **dot**, **xml**, **none** or **failures**. Default type is **text**. The various output types are documented below. The *ENCODING* specifies the output encoding, the default is that of your locale. Valid encodings are listed at https://docs.python.org/library/codecs.html#standard-encodings. Command line option: :option:`--output`" msgstr "" #: ../../src/man/linkcheckerrc.rst:207 msgid "**verbose=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:206 msgid "If set log all checked URLs once, overriding **warnings**. Default is to log only errors and warnings. Command line option: :option:`--verbose`" msgstr "" #: ../../src/man/linkcheckerrc.rst:210 msgid "**warnings=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:210 msgid "If set log warnings. Default is to log warnings. Command line option: :option:`--no-warnings`" msgstr "" #: ../../src/man/linkcheckerrc.rst:219 msgid "**ignoreerrors=**\\ *URL_REGEX* [*MESSAGE_REGEX*] (`MULTILINE`_)" msgstr "" #: ../../src/man/linkcheckerrc.rst:213 msgid "Specify regular expressions to ignore errors for matching URLs, one per line. A second regular expression can be specified per line to only ignore matching error messages per corresponding URL. If the second expression is omitted, all errors are ignored. In contrast to filtering_, this happens *after* checking, which allows checking URLs despite certain expected and tolerable errors. Default is to not ignore any errors. Example:" msgstr "" #: ../../src/man/linkcheckerrc.rst:234 msgid "**status=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:233 msgid "Control printing URL checker status messages. Default is 1. Command line option: :option:`--no-status`" msgstr "" #: ../../src/man/linkcheckerrc.rst:243 msgid "**debug=**\\ *STRING*\\ [**,**\\ *STRING*...]" msgstr "" #: ../../src/man/linkcheckerrc.rst:240 msgid "Print debugging output for the given logger. Available debug loggers are **cmdline**, **checking**, **cache**, **plugin** and **all**. **all** is an alias for all available loggers. Command line option: :option:`--debug`" msgstr "" #: ../../src/man/linkcheckerrc.rst:252 msgid "**quiet=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:249 msgid "If set, operate quiet. An alias for **log=none** that also hides application information messages. This is only useful with **fileoutput**, else no results will be output. Command line option: :option:`--quiet`" msgstr "" #: ../../src/man/linkcheckerrc.rst:258 msgid "text" msgstr "" #: ../../src/man/linkcheckerrc.rst:262 #: ../../src/man/linkcheckerrc.rst:310 #: ../../src/man/linkcheckerrc.rst:320 #: ../../src/man/linkcheckerrc.rst:330 #: ../../src/man/linkcheckerrc.rst:348 #: ../../src/man/linkcheckerrc.rst:362 #: ../../src/man/linkcheckerrc.rst:386 #: ../../src/man/linkcheckerrc.rst:394 #: ../../src/man/linkcheckerrc.rst:404 #: ../../src/man/linkcheckerrc.rst:414 msgid "**filename=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:261 msgid "Specify output filename for text logging. Default filename is **linkchecker-out.txt**. Command line option: :option:`--file-output`" msgstr "" #: ../../src/man/linkcheckerrc.rst:266 #: ../../src/man/linkcheckerrc.rst:312 #: ../../src/man/linkcheckerrc.rst:322 #: ../../src/man/linkcheckerrc.rst:332 #: ../../src/man/linkcheckerrc.rst:350 #: ../../src/man/linkcheckerrc.rst:364 #: ../../src/man/linkcheckerrc.rst:396 #: ../../src/man/linkcheckerrc.rst:406 #: ../../src/man/linkcheckerrc.rst:416 msgid "**parts=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:265 msgid "Comma-separated list of parts that have to be logged. See `LOGGER PARTS`_ below. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:270 #: ../../src/man/linkcheckerrc.rst:315 #: ../../src/man/linkcheckerrc.rst:325 #: ../../src/man/linkcheckerrc.rst:334 #: ../../src/man/linkcheckerrc.rst:352 #: ../../src/man/linkcheckerrc.rst:366 #: ../../src/man/linkcheckerrc.rst:389 #: ../../src/man/linkcheckerrc.rst:399 #: ../../src/man/linkcheckerrc.rst:409 #: ../../src/man/linkcheckerrc.rst:418 msgid "**encoding=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:269 msgid "Valid encodings are listed in https://docs.python.org/library/codecs.html#standard-encodings. Default encoding is the system default locale encoding." msgstr "" #: ../../src/man/linkcheckerrc.rst:274 msgid "**wraplength=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:273 msgid "The number of characters at which to wrap each message line. The default is 65. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:282 msgid "*color\\**" msgstr "" #: ../../src/man/linkcheckerrc.rst:277 msgid "Color settings for the various log parts, syntax is *color* or *type*\\ **;**\\ *color*. The *type* can be **bold**, **light**, **blink**, **invert**. The *color* can be **default**, **black**, **red**, **green**, **yellow**, **blue**, **purple**, **cyan**, **white**, **Black**, **Red**, **Green**, **Yellow**, **Blue**, **Purple**, **Cyan** or **White**. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:284 msgid "**colorparent=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:285 msgid "Set parent color. Default is **white**." msgstr "" #: ../../src/man/linkcheckerrc.rst:286 msgid "**colorurl=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:287 msgid "Set URL color. Default is **default**." msgstr "" #: ../../src/man/linkcheckerrc.rst:288 msgid "**colorname=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:289 msgid "Set name color. Default is **default**." msgstr "" #: ../../src/man/linkcheckerrc.rst:290 msgid "**colorreal=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:291 msgid "Set real URL color. Default is **cyan**." msgstr "" #: ../../src/man/linkcheckerrc.rst:292 msgid "**colorbase=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:293 msgid "Set base URL color. Default is **purple**." msgstr "" #: ../../src/man/linkcheckerrc.rst:294 msgid "**colorvalid=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:295 msgid "Set valid color. Default is **bold;green**." msgstr "" #: ../../src/man/linkcheckerrc.rst:296 msgid "**colorinvalid=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:297 msgid "Set invalid color. Default is **bold;red**." msgstr "" #: ../../src/man/linkcheckerrc.rst:298 msgid "**colorinfo=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:299 msgid "Set info color. Default is **default**." msgstr "" #: ../../src/man/linkcheckerrc.rst:300 msgid "**colorwarning=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:301 msgid "Set warning color. Default is **bold;yellow**." msgstr "" #: ../../src/man/linkcheckerrc.rst:302 msgid "**colordltime=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:303 msgid "Set download time color. Default is **default**." msgstr "" #: ../../src/man/linkcheckerrc.rst:305 msgid "**colorreset=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:305 msgid "Set reset color. Default is **default**." msgstr "" #: ../../src/man/linkcheckerrc.rst:308 msgid "gml" msgstr "" #: ../../src/man/linkcheckerrc.rst:311 #: ../../src/man/linkcheckerrc.rst:313 #: ../../src/man/linkcheckerrc.rst:315 #: ../../src/man/linkcheckerrc.rst:321 #: ../../src/man/linkcheckerrc.rst:323 #: ../../src/man/linkcheckerrc.rst:325 #: ../../src/man/linkcheckerrc.rst:331 #: ../../src/man/linkcheckerrc.rst:333 #: ../../src/man/linkcheckerrc.rst:335 #: ../../src/man/linkcheckerrc.rst:349 #: ../../src/man/linkcheckerrc.rst:351 #: ../../src/man/linkcheckerrc.rst:353 #: ../../src/man/linkcheckerrc.rst:363 #: ../../src/man/linkcheckerrc.rst:365 #: ../../src/man/linkcheckerrc.rst:367 #: ../../src/man/linkcheckerrc.rst:387 #: ../../src/man/linkcheckerrc.rst:389 #: ../../src/man/linkcheckerrc.rst:395 #: ../../src/man/linkcheckerrc.rst:397 #: ../../src/man/linkcheckerrc.rst:399 #: ../../src/man/linkcheckerrc.rst:405 #: ../../src/man/linkcheckerrc.rst:407 #: ../../src/man/linkcheckerrc.rst:409 #: ../../src/man/linkcheckerrc.rst:415 #: ../../src/man/linkcheckerrc.rst:417 #: ../../src/man/linkcheckerrc.rst:419 msgid "See :ref:`[text] ` section above." msgstr "" #: ../../src/man/linkcheckerrc.rst:318 msgid "dot" msgstr "" #: ../../src/man/linkcheckerrc.rst:328 msgid "csv" msgstr "" #: ../../src/man/linkcheckerrc.rst:336 #: ../../src/man/linkcheckerrc.rst:357 msgid "**separator=**\\ *CHAR*" msgstr "" #: ../../src/man/linkcheckerrc.rst:337 msgid "Set CSV separator. Default is a semicolon (**;**)." msgstr "" #: ../../src/man/linkcheckerrc.rst:338 msgid "**quotechar=**\\ *CHAR*" msgstr "" #: ../../src/man/linkcheckerrc.rst:339 msgid "Set CSV quote character. Default is a double quote (**\"**)." msgstr "" #: ../../src/man/linkcheckerrc.rst:343 msgid "**dialect=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:341 msgid "Controls the output formatting. See https://docs.python.org/3/library/csv.html#csv.Dialect. Default is **excel**." msgstr "" #: ../../src/man/linkcheckerrc.rst:346 msgid "sql" msgstr "" #: ../../src/man/linkcheckerrc.rst:354 msgid "**dbname=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:355 msgid "Set database name to store into. Default is **linksdb**." msgstr "" #: ../../src/man/linkcheckerrc.rst:357 msgid "Set SQL command separator character. Default is a semicolon (**;**)." msgstr "" #: ../../src/man/linkcheckerrc.rst:360 msgid "html" msgstr "" #: ../../src/man/linkcheckerrc.rst:368 msgid "**colorbackground=**\\ *COLOR*" msgstr "" #: ../../src/man/linkcheckerrc.rst:369 msgid "Set HTML background color. Default is **#fff7e5**." msgstr "" #: ../../src/man/linkcheckerrc.rst:370 msgid "**colorurl=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:371 msgid "Set HTML URL color. Default is **#dcd5cf**." msgstr "" #: ../../src/man/linkcheckerrc.rst:372 msgid "**colorborder=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:373 msgid "Set HTML border color. Default is **#000000**." msgstr "" #: ../../src/man/linkcheckerrc.rst:374 msgid "**colorlink=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:375 msgid "Set HTML link color. Default is **#191c83**." msgstr "" #: ../../src/man/linkcheckerrc.rst:376 msgid "**colorwarning=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:377 msgid "Set HTML warning color. Default is **#e0954e**." msgstr "" #: ../../src/man/linkcheckerrc.rst:378 msgid "**colorerror=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:379 msgid "Set HTML error color. Default is **#db4930**." msgstr "" #: ../../src/man/linkcheckerrc.rst:381 msgid "**colorok=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:381 msgid "Set HTML valid color. Default is **#3ba557**." msgstr "" #: ../../src/man/linkcheckerrc.rst:384 msgid "failures" msgstr "" #: ../../src/man/linkcheckerrc.rst:392 msgid "xml" msgstr "" #: ../../src/man/linkcheckerrc.rst:402 msgid "gxml" msgstr "" #: ../../src/man/linkcheckerrc.rst:412 msgid "sitemap" msgstr "" #: ../../src/man/linkcheckerrc.rst:421 msgid "**priority=**\\ *FLOAT*" msgstr "" #: ../../src/man/linkcheckerrc.rst:421 msgid "A number between 0.0 and 1.0 determining the priority. The default priority for the first URL is 1.0, for all child URLs 0.5." msgstr "" #: ../../src/man/linkcheckerrc.rst:424 msgid "**frequency=**\\ [**always**\\ \\|\\ **hourly**\\ \\|\\ **daily**\\ \\|\\ **weekly**\\ \\|\\ **monthly**\\ \\|\\ **yearly**\\ \\|\\ **never**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:424 msgid "How frequently pages are changing. Default is **daily**." msgstr "" #: ../../src/man/linkcheckerrc.rst:427 msgid "LOGGER PARTS" msgstr "" #: ../../src/man/linkcheckerrc.rst:429 msgid "**all**" msgstr "" #: ../../src/man/linkcheckerrc.rst:430 msgid "for all parts" msgstr "" #: ../../src/man/linkcheckerrc.rst:431 msgid "**id**" msgstr "" #: ../../src/man/linkcheckerrc.rst:432 msgid "a unique ID for each logentry" msgstr "" #: ../../src/man/linkcheckerrc.rst:433 msgid "**realurl**" msgstr "" #: ../../src/man/linkcheckerrc.rst:434 msgid "the full url link" msgstr "" #: ../../src/man/linkcheckerrc.rst:435 msgid "**result**" msgstr "" #: ../../src/man/linkcheckerrc.rst:436 msgid "valid or invalid, with messages" msgstr "" #: ../../src/man/linkcheckerrc.rst:437 msgid "**extern**" msgstr "" #: ../../src/man/linkcheckerrc.rst:438 msgid "1 or 0, only in some logger types reported" msgstr "" #: ../../src/man/linkcheckerrc.rst:439 msgid "**base**" msgstr "" #: ../../src/man/linkcheckerrc.rst:440 msgid "base href=..." msgstr "" #: ../../src/man/linkcheckerrc.rst:441 msgid "**name**" msgstr "" #: ../../src/man/linkcheckerrc.rst:442 msgid "name and \"name\"" msgstr "" #: ../../src/man/linkcheckerrc.rst:443 msgid "**parenturl**" msgstr "" #: ../../src/man/linkcheckerrc.rst:444 msgid "if any" msgstr "" #: ../../src/man/linkcheckerrc.rst:445 msgid "**info**" msgstr "" #: ../../src/man/linkcheckerrc.rst:446 msgid "some additional info, e.g. FTP welcome messages" msgstr "" #: ../../src/man/linkcheckerrc.rst:447 msgid "**warning**" msgstr "" #: ../../src/man/linkcheckerrc.rst:448 msgid "warnings" msgstr "" #: ../../src/man/linkcheckerrc.rst:449 msgid "**dltime**" msgstr "" #: ../../src/man/linkcheckerrc.rst:450 msgid "download time" msgstr "" #: ../../src/man/linkcheckerrc.rst:451 msgid "**checktime**" msgstr "" #: ../../src/man/linkcheckerrc.rst:452 msgid "check time" msgstr "" #: ../../src/man/linkcheckerrc.rst:453 msgid "**url**" msgstr "" #: ../../src/man/linkcheckerrc.rst:454 msgid "the original url name, can be relative" msgstr "" #: ../../src/man/linkcheckerrc.rst:455 msgid "**intro**" msgstr "" #: ../../src/man/linkcheckerrc.rst:456 msgid "the blurb at the beginning, \"starting at ...\"" msgstr "" #: ../../src/man/linkcheckerrc.rst:458 msgid "**outro**" msgstr "" #: ../../src/man/linkcheckerrc.rst:458 msgid "the blurb at the end, \"found x errors ...\"" msgstr "" #: ../../src/man/linkcheckerrc.rst:461 msgid "MULTILINE" msgstr "" #: ../../src/man/linkcheckerrc.rst:463 msgid "Some option values can span multiple lines. Each line has to be indented for that to work. Lines starting with a hash (**#**) will be ignored, though they must still be indented." msgstr "" #: ../../src/man/linkcheckerrc.rst:476 msgid "EXAMPLE" msgstr "" #: ../../src/man/linkcheckerrc.rst:492 msgid "All plugins have a separate section. If the section appears in the configuration file the plugin is enabled. Some plugins read extra options in their section." msgstr "" #: ../../src/man/linkcheckerrc.rst:497 msgid "AnchorCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:499 msgid "Checks validity of HTML anchors. When checking local files, URLs with anchors that link to directories e.g. \"example/#anchor\" are not supported. There is no such limitation when using http(s)." msgstr "" #: ../../src/man/linkcheckerrc.rst:504 msgid "LocationInfo" msgstr "" #: ../../src/man/linkcheckerrc.rst:506 msgid "Adds the country and if possible city name of the URL host as info. Needs GeoIP or pygeoip and a local country or city lookup DB installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:510 msgid "RegexCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:512 msgid "Define a regular expression which prints a warning if it matches any content of the checked link. This applies only to valid pages, so we can get their content." msgstr "" #: ../../src/man/linkcheckerrc.rst:522 msgid "**warningregex=**\\ *REGEX*" msgstr "" #: ../../src/man/linkcheckerrc.rst:517 msgid "Use this to check for pages that contain some form of error message, for example \"This page has moved\" or \"Oracle Application error\". *REGEX* should be unquoted." msgstr "" #: ../../src/man/linkcheckerrc.rst:521 msgid "Note that multiple values can be combined in the regular expression, for example \"(This page has moved\\|Oracle Application error)\"." msgstr "" #: ../../src/man/linkcheckerrc.rst:525 msgid "SslCertificateCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:527 msgid "Check SSL certificate expiration date. Only internal https: links will be checked. A domain will only be checked once to avoid duplicate warnings." msgstr "" #: ../../src/man/linkcheckerrc.rst:532 msgid "**sslcertwarndays=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:532 msgid "Configures the expiration warning time in days." msgstr "" #: ../../src/man/linkcheckerrc.rst:535 msgid "HtmlSyntaxCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:537 msgid "Check the syntax of HTML pages by submitting their URLs to the online W3C HTML validator. If a page URL is not accessible to the validator no check is performed and no warning given. See https://validator.w3.org/docs/api.html." msgstr "" #: ../../src/man/linkcheckerrc.rst:544 msgid "The HtmlSyntaxCheck plugin is currently broken and is disabled." msgstr "" #: ../../src/man/linkcheckerrc.rst:547 msgid "HttpHeaderInfo" msgstr "" #: ../../src/man/linkcheckerrc.rst:549 msgid "Print HTTP headers in URL info." msgstr "" #: ../../src/man/linkcheckerrc.rst:553 msgid "**prefixes=**\\ *prefix1*\\ [,*prefix2*]..." msgstr "" #: ../../src/man/linkcheckerrc.rst:552 msgid "List of comma separated header prefixes. For example to display all HTTP headers that start with \"X-\"." msgstr "" #: ../../src/man/linkcheckerrc.rst:556 msgid "CssSyntaxCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:558 msgid "Check the syntax of CSS stylesheets by submitting their URLs to the online W3C CSS validator. If a stylesheet URL is not accessible to the validator no check is performed and no warning given. See https://jigsaw.w3.org/css-validator/manual.html#expert." msgstr "" #: ../../src/man/linkcheckerrc.rst:564 msgid "VirusCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:566 msgid "Checks the page content for virus infections with clamav. A local clamav daemon must be installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:570 msgid "**clamavconf=**\\ *filename*" msgstr "" #: ../../src/man/linkcheckerrc.rst:570 msgid "Filename of **clamd.conf** config file." msgstr "" #: ../../src/man/linkcheckerrc.rst:573 msgid "PdfParser" msgstr "" #: ../../src/man/linkcheckerrc.rst:575 msgid "Parse PDF files for URLs to check. Needs the :pypi:`pdfminer.six` Python package installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:579 msgid "WordParser" msgstr "" #: ../../src/man/linkcheckerrc.rst:581 msgid "Parse Word files for URLs to check. Needs the :pypi:`pywin32` Python extension installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:585 msgid "MarkdownCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:587 msgid "Parse Markdown files for URLs to check." msgstr "" #: ../../src/man/linkcheckerrc.rst:590 msgid "**filename_re=**\\ *REGEX*" msgstr "" #: ../../src/man/linkcheckerrc.rst:590 msgid "Regular expression matching the names of Markdown files." msgstr "" #: ../../src/man/linkcheckerrc.rst:593 msgid "WARNINGS" msgstr "" #: ../../src/man/linkcheckerrc.rst:595 msgid "The following warnings are recognized by **ignorewarnings** and **ignorewarningsforurls**:" msgstr "" #: ../../src/man/linkcheckerrc.rst:598 msgid "**file-anchorcheck-directory**" msgstr "" #: ../../src/man/linkcheckerrc.rst:599 msgid "A local directory with an anchor, not supported by AnchorCheck." msgstr "" #: ../../src/man/linkcheckerrc.rst:600 msgid "**file-missing-slash**" msgstr "" #: ../../src/man/linkcheckerrc.rst:601 msgid "The file: URL is missing a trailing slash." msgstr "" #: ../../src/man/linkcheckerrc.rst:602 msgid "**file-system-path**" msgstr "" #: ../../src/man/linkcheckerrc.rst:603 msgid "The file: path is not the same as the system specific path." msgstr "" #: ../../src/man/linkcheckerrc.rst:604 msgid "**ftp-missing-slash**" msgstr "" #: ../../src/man/linkcheckerrc.rst:605 msgid "The ftp: URL is missing a trailing slash." msgstr "" #: ../../src/man/linkcheckerrc.rst:606 msgid "**http-cookie-store-error**" msgstr "" #: ../../src/man/linkcheckerrc.rst:607 msgid "An error occurred while storing a cookie." msgstr "" #: ../../src/man/linkcheckerrc.rst:608 msgid "**http-empty-content**" msgstr "" #: ../../src/man/linkcheckerrc.rst:609 msgid "The URL had no content." msgstr "" #: ../../src/man/linkcheckerrc.rst:610 msgid "**http-rate-limited**" msgstr "" #: ../../src/man/linkcheckerrc.rst:611 msgid "Too many HTTP requests." msgstr "" #: ../../src/man/linkcheckerrc.rst:612 msgid "**http-redirected**" msgstr "" #: ../../src/man/linkcheckerrc.rst:613 msgid "Redirected to a different URL." msgstr "" #: ../../src/man/linkcheckerrc.rst:614 msgid "**mail-no-mx-host**" msgstr "" #: ../../src/man/linkcheckerrc.rst:615 msgid "The mail MX host could not be found." msgstr "" #: ../../src/man/linkcheckerrc.rst:616 msgid "**url-content-size-zero**" msgstr "" #: ../../src/man/linkcheckerrc.rst:617 msgid "The URL content size is zero." msgstr "" #: ../../src/man/linkcheckerrc.rst:618 msgid "**url-content-too-large**" msgstr "" #: ../../src/man/linkcheckerrc.rst:619 msgid "The URL content size is too large." msgstr "" #: ../../src/man/linkcheckerrc.rst:620 msgid "**url-content-type-unparseable**" msgstr "" #: ../../src/man/linkcheckerrc.rst:621 msgid "The URL content type is not parseable." msgstr "" #: ../../src/man/linkcheckerrc.rst:622 msgid "**url-effective-url**" msgstr "" #: ../../src/man/linkcheckerrc.rst:623 msgid "The effective URL is different from the original." msgstr "" #: ../../src/man/linkcheckerrc.rst:624 msgid "**url-error-getting-content**" msgstr "" #: ../../src/man/linkcheckerrc.rst:625 msgid "Could not get the content of the URL." msgstr "" #: ../../src/man/linkcheckerrc.rst:626 msgid "**url-obfuscated-ip**" msgstr "" #: ../../src/man/linkcheckerrc.rst:627 msgid "The IP is obfuscated." msgstr "" #: ../../src/man/linkcheckerrc.rst:629 msgid "**url-whitespace**" msgstr "" #: ../../src/man/linkcheckerrc.rst:629 msgid "The URL contains leading or trailing whitespace." msgstr "" #: ../../src/man/linkcheckerrc.rst:634 msgid ":manpage:`linkchecker(1)`" msgstr "" linkchecker-10.5.0/doc/i18n/locales/000077500000000000000000000000001466565367000170475ustar00rootroot00000000000000linkchecker-10.5.0/doc/i18n/locales/de/000077500000000000000000000000001466565367000174375ustar00rootroot00000000000000linkchecker-10.5.0/doc/i18n/locales/de/LC_MESSAGES/000077500000000000000000000000001466565367000212245ustar00rootroot00000000000000linkchecker-10.5.0/doc/i18n/locales/de/LC_MESSAGES/index.po000066400000000000000000000134301466565367000226740ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) 2000-2014 Bastian Kleineidam # This file is distributed under the same license as the LinkChecker # package. # FIRST AUTHOR , 2020. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: LinkChecker \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-12-04 19:24+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.13.1\n" #: ../../src/index.rst:6 msgid "Check websites for broken links" msgstr "" #: ../../src/index.rst:9 msgid "Introduction" msgstr "" #: ../../src/index.rst:10 msgid "" "LinkChecker is a free, `GPL `_ licensed website validator. LinkChecker checks " "links in web documents or full websites. It runs on Python 3 systems, " "requiring Python 3.9 or later." msgstr "" #: ../../src/index.rst:15 msgid "" "Visit the project on `GitHub " "`_." msgstr "" #: ../../src/index.rst:18 msgid "Installation" msgstr "" #: ../../src/index.rst:24 msgid "" "The version in the pip repository may be old, to find out how to get the " "latest code, plus platform-specific information and other advice see the " ":doc:`installation document `." msgstr "" #: ../../src/index.rst:29 msgid "Basic usage" msgstr "" #: ../../src/index.rst:30 msgid "" "To check a URL like *http://www.example.org/myhomepage/* it is enough to " "execute:" msgstr "" #: ../../src/index.rst:37 msgid "" "This check will validate recursively all pages starting with " "*http://www.example.org/myhomepage/*. Additionally, all external links " "pointing outside of *www.example.org* will be checked but not recursed " "into." msgstr "" #: ../../src/index.rst:42 msgid "" "Find out more from the manual pages :doc:`man/linkchecker` and " ":doc:`man/linkcheckerrc`." msgstr "" #: ../../src/index.rst:46 msgid "Features" msgstr "" #: ../../src/index.rst:48 msgid "recursive and multithreaded checking and site crawling" msgstr "" #: ../../src/index.rst:49 msgid "" "output in colored or normal text, HTML, SQL, CSV, XML or a sitemap graph " "in different formats" msgstr "" #: ../../src/index.rst:51 msgid "HTTP/1.1, HTTPS, FTP, mailto: and local file links support" msgstr "" #: ../../src/index.rst:52 msgid "restriction of link checking with regular expression filters for URLs" msgstr "" #: ../../src/index.rst:53 msgid "proxy support" msgstr "" #: ../../src/index.rst:54 msgid "username/password authorization for HTTP and FTP" msgstr "" #: ../../src/index.rst:55 msgid "honors robots.txt exclusion protocol" msgstr "" #: ../../src/index.rst:56 msgid "Cookie support" msgstr "" #: ../../src/index.rst:57 msgid "HTML5 support" msgstr "" #: ../../src/index.rst:58 msgid "" ":ref:`Plugin support ` allowing custom page " "checks" msgstr "" #: ../../src/index.rst:59 msgid "Different interfaces: command line and web interface" msgstr "" #: ../../src/index.rst:62 msgid "Screenshots" msgstr "" #: ../../src/index.rst:72 msgid "Commandline interface" msgstr "" #: ../../src/index.rst:73 msgid "WSGI web interface" msgstr "" #: ../../src/index.rst:76 msgid "Test suite status" msgstr "" #: ../../src/index.rst:77 msgid "" "Linkchecker has extensive unit tests to ensure code quality. `GitHub " "Actions `_ is used for continuous " "build and test integration." msgstr "" #: ../../src/index.rst:-1 msgid "Build Status" msgstr "" #: ../../src/index.rst:86 msgid "Icon" msgstr "" #: ../../src/index.rst:88 msgid "" "The project icon is categories/applications-development-web from `Oxygen " "icons `_ copyright KDE " "and licensed under the `GNU LGPL version 3 " "`_ or later." msgstr "" #~ msgid "" #~ "#.. image:: https://travis-" #~ "ci.com/linkchecker/linkchecker.png # :alt: Build" #~ " Status # :target: https://travis-" #~ "ci.com/linkchecker/linkchecker" #~ msgstr "" #~ msgid "See the :doc:`installation document ` for more information." #~ msgstr "" #~ msgid "" #~ ":ref:`Plugin support ` " #~ "allowing custom page checks. Currently " #~ "available are HTML and CSS syntax " #~ "checks, Antivirus checks, and more." #~ msgstr "" #~ msgid "" #~ "... and a lot more check options" #~ " documented in the :doc:`man/linkchecker` " #~ "manual page." #~ msgstr "" #~ msgid "" #~ "Linkchecker has extensive unit tests to" #~ " ensure code quality. `Travis CI " #~ "`_ is used for " #~ "continuous build and test integration." #~ msgstr "" #~ msgid "" #~ "LinkChecker is a free, `GPL " #~ "`_ licensed " #~ "website validator. LinkChecker checks links" #~ " in web documents or full websites." #~ " It runs on Python 3 systems, " #~ "requiring Python 3.6 or later." #~ msgstr "" #~ msgid "" #~ "LinkChecker is a free, `GPL " #~ "`_ licensed " #~ "website validator. LinkChecker checks links" #~ " in web documents or full websites." #~ " It runs on Python 3 systems, " #~ "requiring Python 3.8 or later." #~ msgstr "" #~ msgid "" #~ "HTTP/1.1, HTTPS, FTP, mailto:, news:, " #~ "nntp:, Telnet and local file links " #~ "support" #~ msgstr "" #~ msgid "username/password authorization for HTTP and FTP and Telnet" #~ msgstr "" #~ msgid "" #~ "LinkChecker is a free, `GPL " #~ "`_ " #~ "licensed website validator. LinkChecker checks" #~ " links in web documents or full " #~ "websites. It runs on Python 3 " #~ "systems, requiring Python 3.8 or later." #~ msgstr "" linkchecker-10.5.0/doc/i18n/locales/de/LC_MESSAGES/man.po000066400000000000000000002725001466565367000223450ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE # Copyright (C) 2011 Free Software Foundation, Inc. # Bastian Kleineidam , 2005. # Chris Mayo , 2020. # msgid "" msgstr "" "Project-Id-Version: linkchecker 3.4\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-08-27 18:46+0000\n" "PO-Revision-Date: 2020-09-25 19:04+0100\n" "Last-Translator: Chris Mayo \n" "Language: de_DE\n" "Language-Team: German - Germany <>\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.16.0\n" # type: TH #: ../../src/man/linkchecker.rst:4 msgid "linkchecker" msgstr "linkchecker" # type: SH #: ../../src/man/linkchecker.rst:7 msgid "SYNOPSIS" msgstr "SYNTAX" # type: Plain text #: ../../src/man/linkchecker.rst:9 msgid "**linkchecker** [*options*] [*file-or-url*]..." msgstr "**linkchecker** [*Optionen*] [*Datei-oder-URL*]..." # type: SH #: ../../src/man/linkchecker.rst:12 ../../src/man/linkcheckerrc.rst:7 msgid "DESCRIPTION" msgstr "BESCHREIBUNG" # type: TH #: ../../src/man/linkchecker.rst:14 msgid "LinkChecker features" msgstr "LinkChecker beinhaltet" #: ../../src/man/linkchecker.rst:16 msgid "recursive and multithreaded checking" msgstr "rekursives Prüfen und Multithreading" #: ../../src/man/linkchecker.rst:17 msgid "" "output in colored or normal text, HTML, SQL, CSV, XML or a sitemap graph " "in different formats" msgstr "" "Ausgabe als farbigen oder normalen Text, HTML, SQL, CSV, XML oder einen " "Sitemap-Graphen in verschiedenen Formaten" #: ../../src/man/linkchecker.rst:19 #, fuzzy msgid "support for HTTP/1.1, HTTPS, FTP, mailto: and local file links" msgstr "" "Unterstützung von HTTP/1.1, HTTPS, FTP, mailto:, news:, nntp:, Telnet und" " Verknüpfungen auf lokale Dateien" #: ../../src/man/linkchecker.rst:20 msgid "restriction of link checking with URL filters" msgstr "Einschränkung der Linküberprüfung mit URL-Filter" #: ../../src/man/linkchecker.rst:21 msgid "proxy support" msgstr "Proxy-Unterstützung" #: ../../src/man/linkchecker.rst:22 #, fuzzy msgid "username/password authorization for HTTP and FTP" msgstr "Benutzer/Passwort Authorisierung für HTTP, FTP und Telnet" #: ../../src/man/linkchecker.rst:23 msgid "support for robots.txt exclusion protocol" msgstr "Unterstützung des robots.txt Protokolls" #: ../../src/man/linkchecker.rst:24 msgid "support for Cookies" msgstr "Unterstützung für Cookies" #: ../../src/man/linkchecker.rst:25 msgid "support for HTML5" msgstr "Unterstützung für HTML5" #: ../../src/man/linkchecker.rst:26 msgid "Antivirus check" msgstr "Antivirusprüfung" #: ../../src/man/linkchecker.rst:27 msgid "a command line and web interface" msgstr "ein Kommandozeilenprogramm und web interface" # type: SH #: ../../src/man/linkchecker.rst:30 msgid "EXAMPLES" msgstr "BEISPIELE" # type: Plain text #: ../../src/man/linkchecker.rst:32 msgid "The most common use checks the given domain recursively:" msgstr "Der häufigste Gebrauchsfall prüft die angegebene Domäne rekursiv:" # type: Plain text #: ../../src/man/linkchecker.rst:38 msgid "" "Beware that this checks the whole site which can have thousands of URLs. " "Use the :option:`-r` option to restrict the recursion depth." msgstr "" "Beachten Sie dass dies die komplette Domäne überprüft, welche aus " "mehreren tausend URLs bestehen kann. Benutzen Sie die Option " ":option:`-r`, um die Rekursionstiefe zu beschränken." # type: Plain text #: ../../src/man/linkchecker.rst:41 msgid "" "Don't check URLs with **/secret** in its name. All other links are " "checked as usual:" msgstr "" "Prüfe keine **/secret** URLs. Alle anderen Verknüpfungen werden wie " "üblich geprüft:" # type: Plain text #: ../../src/man/linkchecker.rst:48 msgid "Checking a local HTML file on Unix:" msgstr "Überprüfung einer lokalen HTML Datei unter Unix:" # type: Plain text #: ../../src/man/linkchecker.rst:54 msgid "Checking a local HTML file on Windows:" msgstr "Überprüfung einer lokalen HTML Datei unter Windows:" # type: Plain text #: ../../src/man/linkchecker.rst:60 msgid "You can skip the **http://** url part if the domain starts with **www.**:" msgstr "" "Sie können den **http://** URL Anteil weglassen wenn die Domäne mit " "**www.** beginnt:" # type: Plain text #: ../../src/man/linkchecker.rst:67 msgid "You can skip the **ftp://** url part if the domain starts with **ftp.**:" msgstr "" "Sie können den **ftp://** URL Anteil weglassen wenn die Domäne mit " "**ftp.** beginnt:" # type: Plain text #: ../../src/man/linkchecker.rst:73 msgid "Generate a sitemap graph and convert it with the graphviz dot utility:" msgstr "" "Erzeuge einen Sitemap Graphen und konvertiere ihn mit dem graphviz dot " "Programm:" # type: SH #: ../../src/man/linkchecker.rst:80 msgid "OPTIONS" msgstr "OPTIONEN" # type: SS #: ../../src/man/linkchecker.rst:83 msgid "General options" msgstr "Allgemeine Optionen" # type: Plain text #: ../../src/man/linkchecker.rst:87 #, fuzzy msgid "" "Use FILENAME as configuration file. By default LinkChecker uses " "$XDG_CONFIG_HOME/linkchecker/linkcheckerrc." msgstr "" "Benutze DATEINAME als Konfigurationsdatei. Standardmäßig benutzt " "LinkChecker ~/.linkchecker/linkcheckerrc." # type: Plain text #: ../../src/man/linkchecker.rst:92 msgid "Help me! Print usage information for this program." msgstr "Hilfe! Gebe Gebrauchsanweisung für dieses Programm aus." # type: Plain text #: ../../src/man/linkchecker.rst:96 msgid "" "Generate no more than the given number of threads. Default number of " "threads is 10. To disable threading specify a non-positive number." msgstr "" "Generiere nicht mehr als die angegebene Anzahl von Threads. Die " "Standardanzahl von Threads ist 10. Um Threads zu deaktivieren, geben Sie " "eine nicht positive Nummer an." # type: Plain text #: ../../src/man/linkchecker.rst:101 msgid "Print version and exit." msgstr "Gebe die Version aus und beende das Programm." # type: Plain text #: ../../src/man/linkchecker.rst:105 msgid "Print available check plugins and exit." msgstr "" # type: SS #: ../../src/man/linkchecker.rst:108 msgid "Output options" msgstr "Ausgabeoptionen" #: ../../src/man/linkchecker.rst:111 ../../src/man/linkcheckerrc.rst:187 msgid "URL checking results" msgstr "" #: ../../src/man/linkchecker.rst:115 #, fuzzy msgid "" "Output to a file linkchecker-out.TYPE, " "$XDG_DATA_HOME/linkchecker/failures for the failures output type, or " "FILENAME if specified. The ENCODING specifies the output encoding, the " "default is that of your locale. Valid encodings are listed at " "https://docs.python.org/library/codecs.html#standard-encodings. The " "FILENAME and ENCODING parts of the none output type will be ignored, else" " if the file already exists, it will be overwritten. You can specify this" " option more than once. Valid file output TYPEs are text, html, sql, csv," " gml, dot, xml, sitemap, none or failures. Default is no file output. The" " various output types are documented below. Note that you can suppress " "all console output with the option :option:`-o` *none*." msgstr "" "Ausgabe in eine Datei namens linkchecker-out.TYP, " "$HOME/.linkchecker/failures bei failures Ausgabe, oder DATEINAME falls " "angegeben. Das ENCODING gibt die Ausgabekodierung an. Der Standard ist " "das der lokalen Spracheinstellung. Gültige Enkodierungen sind aufgelistet" " unter https://docs.python.org/library/codecs.html#standard-encodings. " "Der DATEINAME und ENKODIERUNG Teil wird beim Ausgabetyp none ignoriert, " "ansonsten wird die Datei überschrieben falls sie existiert. Sie können " "diese Option mehr als einmal verwenden. Gültige Ausgabetypen sind text, " "html, sql, csv, gml, dot, xml, sitemap, none oder failures. Standard ist " "keine Dateiausgabe. Die unterschiedlichen Ausgabetypen sind weiter unten " "dokumentiert. Beachten Sie, dass Sie mit der Option :option:`-o` *none* " "jegliche Ausgaben auf der Konsole verhindern können." # type: Plain text #: ../../src/man/linkchecker.rst:131 msgid "Don't log warnings. Default is to log warnings." msgstr "Gebe keine Warnungen aus. Standard ist die Ausgabe von Warnungen." #: ../../src/man/linkchecker.rst:135 #, fuzzy msgid "" "Specify the console output type as text, html, sql, csv, gml, dot, xml, " "sitemap, none or failures. Default type is text. The various output types" " are documented below. The ENCODING specifies the output encoding, the " "default is that of your locale. Valid encodings are listed at " "https://docs.python.org/library/codecs.html#standard-encodings." msgstr "" "Gib Ausgabetyp als text, html, sql, csv, gml, dot, xml, sitemap, none " "oder failures an. Stadard Typ ist text. Die verschiedenen Ausgabetypen " "sind unten dokumentiert. Das ENCODING gibt die Ausgabekodierung an. Der " "Standard ist das der lokalen Spracheinstellung. Gültige Enkodierungen " "sind aufgelistet unter https://docs.python.org/library/codecs.html" "#standard-encodings." # type: Plain text #: ../../src/man/linkchecker.rst:144 #, fuzzy msgid "" "Log all checked URLs, overriding :option:`--no-warnings`. Default is to " "log only errors and warnings." msgstr "" "Gebe alle geprüften URLs aus. Standard ist es, nur fehlerhafte URLs und " "Warnungen auszugeben." #: ../../src/man/linkchecker.rst:148 ../../src/man/linkcheckerrc.rst:230 msgid "Progress updates" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:152 #, fuzzy msgid "Do not print URL check status messages." msgstr "Gebe keine Statusmeldungen aus." # type: SS #: ../../src/man/linkchecker.rst:155 ../../src/man/linkcheckerrc.rst:237 #, fuzzy msgid "Application" msgstr "authentication" #: ../../src/man/linkchecker.rst:159 msgid "" "Print debugging output for the given logger. Available debug loggers are " "cmdline, checking, cache, plugin and all. all is an alias for all " "available loggers. This option can be given multiple times to debug with " "more than one logger." msgstr "" #: ../../src/man/linkchecker.rst:165 ../../src/man/linkcheckerrc.rst:246 msgid "Quiet" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:169 #, fuzzy msgid "" "Quiet operation, an alias for :option:`-o` *none* that also hides " "application information messages. This is only useful with :option:`-F`, " "else no results will be output." msgstr "" "Keine Ausgabe, ein Alias für :option:`-o` *none*. Dies ist nur in " "Verbindung mit :option:`-F` nützlich." # type: SS #: ../../src/man/linkchecker.rst:174 msgid "Checking options" msgstr "Optionen zum Prüfen" # type: Plain text #: ../../src/man/linkchecker.rst:178 #, fuzzy msgid "" "Use initial cookie data read from a file. The cookie data format is " "explained below." msgstr "" "Lese eine Datei mit Cookie-Daten. Das Cookie Datenformat wird weiter " "unten erklärt." #: ../../src/man/linkchecker.rst:183 msgid "Check external URLs." msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:187 msgid "" "URLs matching the given regular expression will only be syntax checked. " "This option can be given multiple times. See section `REGULAR " "EXPRESSIONS`_ for more info." msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:193 msgid "" "Check but do not recurse into URLs matching the given regular expression." " This option can be given multiple times. See section `REGULAR " "EXPRESSIONS`_ for more info." msgstr "" "Prüfe URLs die auf den regulären Ausdruck zutreffen, aber führe keine " "Rekursion durch. Diese Option kann mehrmals angegeben werden. Siehe " "Abschnitt `REGULAR EXPRESSIONS`_ für weitere Infos." #: ../../src/man/linkchecker.rst:200 msgid "Check URLs regardless of any robots.txt files." msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:204 msgid "" "Read a password from console and use it for HTTP and FTP authorization. " "For FTP the default password is anonymous@. For HTTP there is no default " "password. See also :option:`-u`." msgstr "" "Liest ein Passwort von der Kommandozeile und verwende es für HTTP und FTP" " Autorisierung. Für FTP ist das Standardpasswort anonymous@. Für HTTP " "gibt es kein Standardpasswort. Siehe auch :option:`-u`." # type: Plain text #: ../../src/man/linkchecker.rst:210 msgid "" "Check recursively all links up to given depth. A negative depth will " "enable infinite recursion. Default depth is infinite." msgstr "" "Prüfe rekursiv alle URLs bis zu der angegebenen Tiefe. Eine negative " "Tiefe bewirkt unendliche Rekursion. Standard Tiefe ist unendlich." # type: Plain text #: ../../src/man/linkchecker.rst:215 msgid "" "Set the timeout for connection attempts in seconds. The default timeout " "is 60 seconds." msgstr "" "Setze den Timeout für TCP-Verbindungen in Sekunden. Der Standard Timeout " "ist 60 Sekunden." # type: Plain text #: ../../src/man/linkchecker.rst:220 msgid "" "Try the given username for HTTP and FTP authorization. For FTP the " "default username is anonymous. For HTTP there is no default username. See" " also :option:`-p`." msgstr "" "Verwende den angegebenen Benutzernamen für HTTP und FTP Autorisierung. " "Für FTP ist der Standardname anonymous. Für HTTP gibt es keinen " "Standardnamen. Siehe auch :option:`-p`." #: ../../src/man/linkchecker.rst:226 msgid "" "Specify the User-Agent string to send to the HTTP server, for example " "\"Mozilla/4.0\". The default is \"LinkChecker/X.Y\" where X.Y is the " "current version of LinkChecker." msgstr "" "Gibt den User-Agent an, der zu HTTP-Servern geschickt wird, z.B. " "\"Mozilla/4.0\". Der Standard ist \"LinkChecker/X.Y\", wobei X.Y die " "aktuelle Version von LinkChecker ist." # type: SS #: ../../src/man/linkchecker.rst:231 #, fuzzy msgid "Input options" msgstr "Ausgabeoptionen" # type: Plain text #: ../../src/man/linkchecker.rst:235 #, fuzzy msgid "Read from stdin a list of white-space separated URLs to check." msgstr "" "Lese Liste von URLs zum Prüfen von der Standardeingabe, getrennt durch " "Leerzeichen." #: ../../src/man/linkchecker.rst:239 msgid "" "The location to start checking with. A file can be a simple list of URLs," " one per line, if the first line is \"# LinkChecker URL list\"." msgstr "" # type: SH #: ../../src/man/linkchecker.rst:244 msgid "CONFIGURATION FILES" msgstr "KONFIGURATIONSDATEIEN" # type: Plain text #: ../../src/man/linkchecker.rst:246 msgid "" "Configuration files can specify all options above. They can also specify " "some options that cannot be set on the command line. See " ":manpage:`linkcheckerrc(5)` for more info." msgstr "" "Konfigurationsdateien können alle obigen Optionen enthalten. Sie können " "zudem Optionen enthalten, welche nicht auf der Kommandozeile gesetzt " "werden können. Siehe :manpage:`linkcheckerrc(5)` für mehr Informationen." # type: SH #: ../../src/man/linkchecker.rst:251 ../../src/man/linkcheckerrc.rst:255 msgid "OUTPUT TYPES" msgstr "AUSGABETYPEN" # type: Plain text #: ../../src/man/linkchecker.rst:253 msgid "" "Note that by default only errors and warnings are logged. You should use " "the option :option:`--verbose` to get the complete URL list, especially " "when outputting a sitemap graph format." msgstr "" "Beachten Sie, dass standardmäßig nur Fehler und Warnungen protokolliert " "werden. Sie sollten die :option:`--verbose` Option benutzen, um eine " "komplette URL Liste zu erhalten, besonders bei Ausgabe eines Sitemap-" "Graphen." #: ../../src/man/linkchecker.rst:257 msgid "**text**" msgstr "**text**" # type: Plain text #: ../../src/man/linkchecker.rst:258 msgid "Standard text logger, logging URLs in keyword: argument fashion." msgstr "Standard Textausgabe in \"Schlüssel: Wert\"-Form." #: ../../src/man/linkchecker.rst:261 msgid "**html**" msgstr "**html**" # type: Plain text #: ../../src/man/linkchecker.rst:260 msgid "" "Log URLs in keyword: argument fashion, formatted as HTML. Additionally " "has links to the referenced pages. Invalid URLs have HTML and CSS syntax " "check links appended." msgstr "" "Gebe URLs in \"Schlüssel: Wert\"-Form als HTML formatiert aus. Besitzt " "zudem Verknüpfungen auf die referenzierten Seiten. Ungültige URLs haben " "Verknüpfungen zur HTML und CSS Syntaxprüfung angehängt." #: ../../src/man/linkchecker.rst:263 msgid "**csv**" msgstr "**csv**" # type: Plain text #: ../../src/man/linkchecker.rst:264 msgid "Log check result in CSV format with one URL per line." msgstr "Gebe Prüfresultat in CSV-Format aus mit einer URL pro Zeile." #: ../../src/man/linkchecker.rst:266 msgid "**gml**" msgstr "**gml**" # type: Plain text #: ../../src/man/linkchecker.rst:266 msgid "Log parent-child relations between linked URLs as a GML sitemap graph." msgstr "Gebe Vater-Kind Beziehungen zwischen verknüpften URLs als GML Graphen aus." #: ../../src/man/linkchecker.rst:269 msgid "**dot**" msgstr "**dot**" # type: Plain text #: ../../src/man/linkchecker.rst:269 msgid "Log parent-child relations between linked URLs as a DOT sitemap graph." msgstr "Gebe Vater-Kind Beziehungen zwischen verknüpften URLs als DOT Graphen aus." #: ../../src/man/linkchecker.rst:271 msgid "**gxml**" msgstr "**gxml**" # type: Plain text #: ../../src/man/linkchecker.rst:272 msgid "Log check result as a GraphXML sitemap graph." msgstr "Gebe Prüfresultat als GraphXML-Datei aus." #: ../../src/man/linkchecker.rst:273 msgid "**xml**" msgstr "**xml**" # type: Plain text #: ../../src/man/linkchecker.rst:274 msgid "Log check result as machine-readable XML." msgstr "Gebe Prüfresultat als maschinenlesbare XML-Datei aus." #: ../../src/man/linkchecker.rst:276 msgid "**sitemap**" msgstr "**sitemap**" #: ../../src/man/linkchecker.rst:276 msgid "" "Log check result as an XML sitemap whose protocol is documented at " "https://www.sitemaps.org/protocol.html." msgstr "" "Protokolliere Prüfergebnisse als XML Sitemap dessen Format unter " "https://www.sitemaps.org/protocol.html dokumentiert ist." #: ../../src/man/linkchecker.rst:279 msgid "**sql**" msgstr "**sql**" # type: Plain text #: ../../src/man/linkchecker.rst:279 msgid "" "Log check result as SQL script with INSERT commands. An example script to" " create the initial SQL table is included as create.sql." msgstr "" "Gebe Prüfresultat als SQL Skript mit INSERT Befehlen aus. Ein " "Beispielskript, um die initiale SQL Tabelle zu erstellen ist unter " "create.sql zu finden." #: ../../src/man/linkchecker.rst:283 msgid "**failures**" msgstr "**failures**" # type: Plain text #: ../../src/man/linkchecker.rst:282 #, fuzzy msgid "" "Suitable for cron jobs. Logs the check result into a file " "**$XDG_DATA_HOME/linkchecker/failures** which only contains entries with " "invalid URLs and the number of times they have failed." msgstr "" "Für Cronjobs geeignet. Gibt das Prüfergebnis in eine Datei " "**~/.linkchecker/failures** aus, welche nur Einträge mit fehlerhaften " "URLs und die Anzahl der Fehlversuche enthält." #: ../../src/man/linkchecker.rst:286 msgid "**none**" msgstr "**none**" # type: Plain text #: ../../src/man/linkchecker.rst:286 msgid "Logs nothing. Suitable for debugging or checking the exit code." msgstr "Gibt nichts aus. Für Debugging oder Prüfen des Rückgabewerts geeignet." # type: SH #: ../../src/man/linkchecker.rst:289 msgid "REGULAR EXPRESSIONS" msgstr "REGULÄRE AUSDRÜCKE" # type: Plain text #: ../../src/man/linkchecker.rst:291 msgid "" "LinkChecker accepts Python regular expressions. See " "https://docs.python.org/howto/regex.html for an introduction. An addition" " is that a leading exclamation mark negates the regular expression." msgstr "" "LinkChecker akzeptiert Pythons reguläre Ausdrücke. Siehe " "https://docs.python.org/howto/regex.html für eine Einführung. Eine " "Ergänzung ist, dass ein regulärer Ausdruck negiert wird falls er mit " "einem Ausrufezeichen beginnt." # type: SH #: ../../src/man/linkchecker.rst:297 msgid "COOKIE FILES" msgstr "COOKIE-DATEIEN" # type: Plain text #: ../../src/man/linkchecker.rst:299 msgid "" "A cookie file contains standard HTTP header (RFC 2616) data with the " "following possible names:" msgstr "" "Eine Cookie-Datei enthält Standard HTTP-Header (RFC 2616) mit den " "folgenden möglichen Namen:" # type: TP #: ../../src/man/linkchecker.rst:302 msgid "**Host** (required)" msgstr "**Host** (erforderlich)" # type: Plain text #: ../../src/man/linkchecker.rst:303 msgid "Sets the domain the cookies are valid for." msgstr "Setzt die Domäne für die die Cookies gültig sind." # type: TP #: ../../src/man/linkchecker.rst:304 msgid "**Path** (optional)" msgstr "**Path** (optional)" # type: Plain text #: ../../src/man/linkchecker.rst:305 msgid "Gives the path the cookies are value for; default path is **/**." msgstr "Gibt den Pfad für den die Cookies gültig sind; Standardpfad ist **/**." # type: TP #: ../../src/man/linkchecker.rst:307 msgid "**Set-cookie** (required)" msgstr "**Set-cookie** (erforderlich)" # type: Plain text #: ../../src/man/linkchecker.rst:307 msgid "Set cookie name/value. Can be given more than once." msgstr "Setzt den Cookie Name/Wert. Kann mehrmals angegeben werden." # type: Plain text #: ../../src/man/linkchecker.rst:309 msgid "" "Multiple entries are separated by a blank line. The example below will " "send two cookies to all URLs starting with **http://example.com/hello/** " "and one to all URLs starting with **https://example.org/**:" msgstr "" "Mehrere Einträge sind durch eine Leerzeile zu trennen. Das untige " "Beispiel sendet zwei Cookies zu allen URLs die mit " "**http://example.org/hello/** beginnen, und eins zu allen URLs die mit " "**https://example.org** beginnen:" # type: SH #: ../../src/man/linkchecker.rst:327 msgid "PROXY SUPPORT" msgstr "PROXY UNTERSTÜTZUNG" # type: Plain text #: ../../src/man/linkchecker.rst:329 #, fuzzy msgid "" "To use a proxy on Unix or Windows set the :envvar:`http_proxy` or " ":envvar:`https_proxy` environment variables to the proxy URL. The URL " "should be of the form **http://**\\ [*user*\\ **:**\\ *pass*\\ **@**]\\ " "*host*\\ [**:**\\ *port*]. LinkChecker also detects manual proxy settings" " of Internet Explorer under Windows systems. On a Mac use the Internet " "Config to select a proxy. You can also set a comma-separated domain list " "in the :envvar:`no_proxy` environment variable to ignore any proxy " "settings for these domains. The :envvar:`curl_ca_bundle` environment " "variable can be used to identify an alternative certificate bundle to be " "used with an HTTPS proxy." msgstr "" "Um einen Proxy unter Unix oder Windows zu benutzen, setzen Sie die " ":envvar:`http_proxy`, :envvar:`https_proxy` oder :envvar:`ftp_proxy` " "Umgebungsvariablen auf die Proxy URL. Die URL sollte die Form " "**http://**\\ [*user*\\ **:**\\ *pass*\\ **@**]\\ *host*\\ [**:**\\ " "*port*] besitzen. LinkChecker erkennt auch die Proxy-Einstellungen des " "Internet Explorers auf einem Windows-System, und GNOME oder KDE auf Linux" " Systemen. Auf einem Mac benutzen Sie die Internet Konfiguration. Sie " "können eine komma-separierte Liste von Domainnamen in der " ":envvar:`no_proxy` Umgebungsvariable setzen, um alle Proxies für diese " "Domainnamen zu ignorieren." # type: Plain text #: ../../src/man/linkchecker.rst:341 msgid "Setting a HTTP proxy on Unix for example looks like this:" msgstr "Einen HTTP-Proxy unter Unix anzugeben sieht beispielsweise so aus:" # type: Plain text #: ../../src/man/linkchecker.rst:347 msgid "Proxy authentication is also supported:" msgstr "Proxy-Authentifizierung wird ebenfalls unterstützt:" # type: Plain text #: ../../src/man/linkchecker.rst:353 msgid "Setting a proxy on the Windows command prompt:" msgstr "Setzen eines Proxies unter der Windows Befehlszeile:" #: ../../src/man/linkchecker.rst:360 msgid "PERFORMED CHECKS" msgstr "Durchgeführte Prüfungen" #: ../../src/man/linkchecker.rst:362 msgid "" "All URLs have to pass a preliminary syntax test. Minor quoting mistakes " "will issue a warning, all other invalid syntax issues are errors. After " "the syntax check passes, the URL is queued for connection checking. All " "connection check types are described below." msgstr "" "Alle URLs müssen einen ersten Syntaxtest bestehen. Kleine " "Kodierungsfehler ergeben eine Warnung, jede andere ungültige Syntaxfehler" " sind Fehler. Nach dem Bestehen des Syntaxtests wird die URL in die " "Schlange zum Verbindungstest gestellt. Alle Verbindungstests sind weiter " "unten beschrieben." #: ../../src/man/linkchecker.rst:373 msgid "HTTP links (**http:**, **https:**)" msgstr "HTTP Verknüpfungen (**http:**, **https:**)" #: ../../src/man/linkchecker.rst:368 msgid "" "After connecting to the given HTTP server the given path or query is " "requested. All redirections are followed, and if user/password is given " "it will be used as authorization when necessary. All final HTTP status " "codes other than 2xx are errors." msgstr "" "Nach Verbinden zu dem gegebenen HTTP-Server wird der eingegebene Pfad " "oder Query angefordert. Alle Umleitungen werden verfolgt, und falls ein " "Benutzer/Passwort angegeben wurde werden diese falls notwendig als " "Authorisierung benutzt. Alle finalen HTTP Statuscodes, die nicht dem " "Muster 2xx entsprechen, werden als Fehler ausgegeben." #: ../../src/man/linkchecker.rst:373 msgid "HTML page contents are checked for recursion." msgstr "Der Inhalt von HTML-Seiten wird rekursiv geprüft." #: ../../src/man/linkchecker.rst:380 msgid "Local files (**file:**)" msgstr "Lokale Dateien (**file:**)" #: ../../src/man/linkchecker.rst:376 msgid "" "A regular, readable file that can be opened is valid. A readable " "directory is also valid. All other files, for example device files, " "unreadable or non-existing files are errors." msgstr "" "Eine reguläre, lesbare Datei die geöffnet werden kann ist gültig. Ein " "lesbares Verzeichnis ist ebenfalls gültig. Alle anderen Dateien, zum " "Beispiel Gerätedateien, unlesbare oder nicht existente Dateien ergeben " "einen Fehler." #: ../../src/man/linkchecker.rst:380 msgid "HTML or other parseable file contents are checked for recursion." msgstr "HTML- oder andere untersuchbare Dateiinhalte werden rekursiv geprüft." #: ../../src/man/linkchecker.rst:395 msgid "Mail links (**mailto:**)" msgstr "Mail-Links (**mailto:**)" #: ../../src/man/linkchecker.rst:383 msgid "" "A mailto: link eventually resolves to a list of email addresses. If one " "address fails, the whole list will fail. For each mail address we check " "the following things:" msgstr "" "Ein mailto:-Link ergibt eine Liste von E-Mail-Adressen. Falls eine " "Adresse fehlerhaft ist, wird die ganze Liste als fehlerhaft angesehen. " "Für jede E-Mail-Adresse werden die folgenden Dinge geprüft:" #: ../../src/man/linkchecker.rst:387 msgid "Check the address syntax, both the parts before and after the @ sign." msgstr "" #: ../../src/man/linkchecker.rst:389 msgid "Look up the MX DNS records. If we found no MX record, print an error." msgstr "" #: ../../src/man/linkchecker.rst:391 msgid "" "Check if one of the mail hosts accept an SMTP connection. Check hosts " "with higher priority first. If no host accepts SMTP, we print a warning." msgstr "" #: ../../src/man/linkchecker.rst:394 msgid "" "Try to verify the address with the VRFY command. If we got an answer, " "print the verified address as an info." msgstr "" #: ../../src/man/linkchecker.rst:404 msgid "FTP links (**ftp:**)" msgstr "FTP-Links (**ftp:**)" #: ../../src/man/linkchecker.rst:398 msgid "For FTP links we do:" msgstr "Für FTP-Links wird Folgendes geprüft:" #: ../../src/man/linkchecker.rst:400 msgid "connect to the specified host" msgstr "Eine Verbindung zum angegeben Rechner wird aufgebaut" #: ../../src/man/linkchecker.rst:401 msgid "" "try to login with the given user and password. The default user is " "**anonymous**, the default password is **anonymous@**." msgstr "" "Versuche, sich mit dem gegebenen Nutzer und Passwort anzumelden. Der " "Standardbenutzer ist ``anonymous``, das Standardpasswort ist " "``anonymous@``." #: ../../src/man/linkchecker.rst:403 msgid "try to change to the given directory" msgstr "Versuche, in das angegebene Verzeichnis zu wechseln" #: ../../src/man/linkchecker.rst:404 msgid "list the file with the NLST command" msgstr "Liste die Dateien im Verzeichnis auf mit dem NLST-Befehl" #: ../../src/man/linkchecker.rst:413 msgid "Unsupported links (**javascript:**, etc.)" msgstr "Nicht unterstützte Links (**javascript:**, etc.)" #: ../../src/man/linkchecker.rst:407 msgid "" "An unsupported link will only print a warning. No further checking will " "be made." msgstr "" "Ein nicht unterstützter Link wird nur eine Warnung ausgeben. Weitere " "Prüfungen werden nicht durchgeführt." #: ../../src/man/linkchecker.rst:410 msgid "" "The complete list of recognized, but unsupported links can be found in " "the `linkcheck/checker/unknownurl.py " "`__" " source file. The most prominent of them should be JavaScript links." msgstr "" "Die komplette Liste von erkannten, aber nicht unterstützten Links ist in " "der Quelldatei `linkcheck/checker/unknownurl.py " "`__." " Die bekanntesten davon dürften JavaScript-Links sein." #: ../../src/man/linkchecker.rst:416 #, fuzzy msgid "SITEMAPS" msgstr "sitemap" #: ../../src/man/linkchecker.rst:418 msgid "" "Sitemaps are parsed for links to check and can be detected either from a " "sitemap entry in a robots.txt, or when passed as a :option:`FILE-OR-URL` " "argument in which case detection requires the urlset/sitemapindex tag to " "be within the first 70 characters of the sitemap. Compressed sitemap " "files are not supported." msgstr "" #: ../../src/man/linkchecker.rst:425 ../../src/man/linkcheckerrc.rst:490 msgid "PLUGINS" msgstr "" #: ../../src/man/linkchecker.rst:427 msgid "" "There are two plugin types: connection and content plugins. Connection " "plugins are run after a successful connection to the URL host. Content " "plugins are run if the URL type has content (mailto: URLs have no content" " for example) and if the check is not forbidden (ie. by HTTP robots.txt)." " Use the option :option:`--list-plugins` for a list of plugins and their " "documentation. All plugins are enabled via the " ":manpage:`linkcheckerrc(5)` configuration file." msgstr "" # type: SH #: ../../src/man/linkchecker.rst:437 msgid "RECURSION" msgstr "Rekursion" #: ../../src/man/linkchecker.rst:439 msgid "" "Before descending recursively into a URL, it has to fulfill several " "conditions. They are checked in this order:" msgstr "" "Bevor eine URL rekursiv geprüft wird, hat diese mehrere Bedingungen zu " "erfüllen. Diese werden in folgender Reihenfolge geprüft:" #: ../../src/man/linkchecker.rst:442 msgid "A URL must be valid." msgstr "Eine URL muss gültig sein." #: ../../src/man/linkchecker.rst:443 msgid "" "A URL must be parseable. This currently includes HTML files, Opera " "bookmarks files, and directories. If a file type cannot be determined " "(for example it does not have a common HTML file extension, and the " "content does not look like HTML), it is assumed to be non-parseable." msgstr "" "Der URL-Inhalt muss analysierbar sein. Dies beinhaltet zur Zeit HTML-" "Dateien, Opera Lesezeichen, und Verzeichnisse. Falls ein Dateityp nicht " "erkannt wird, (zum Beispiel weil er keine bekannte HTML-Dateierweiterung " "besitzt, und der Inhalt nicht nach HTML aussieht), wird der Inhalt als " "nicht analysierbar angesehen." #: ../../src/man/linkchecker.rst:447 msgid "" "The URL content must be retrievable. This is usually the case except for " "example mailto: or unknown URL types." msgstr "" "Der URL-Inhalt muss ladbar sein. Dies ist normalerweise der Fall, mit " "Ausnahme von mailto: oder unbekannten URL-Typen." #: ../../src/man/linkchecker.rst:449 msgid "" "The maximum recursion level must not be exceeded. It is configured with " "the :option:`--recursion-level` option and is unlimited per default." msgstr "" "Die maximale Rekursionstiefe darf nicht überschritten werden. Diese wird " "mit der Option :option:`--recursion-level` konfiguriert und ist " "standardmäßig nicht limitiert." #: ../../src/man/linkchecker.rst:451 msgid "" "It must not match the ignored URL list. This is controlled with the " ":option:`--ignore-url` option." msgstr "" "Die URL darf nicht in der Liste von ignorierten URLs sein. Die " "ignorierten URLs werden mit der Option :option:`--ignore-url` " "konfiguriert." #: ../../src/man/linkchecker.rst:453 msgid "" "The Robots Exclusion Protocol must allow links in the URL to be followed " "recursively. This is checked by searching for a \"nofollow\" directive in" " the HTML header data." msgstr "" "Das Robots Exclusion Protocol muss es erlauben, dass Verknüpfungen in der" " URL rekursiv verfolgt werden können. Dies wird geprüft, indem in den " "HTML Kopfdaten nach der \"nofollow\"-Direktive gesucht wird." #: ../../src/man/linkchecker.rst:457 msgid "" "Note that the directory recursion reads all files in that directory, not " "just a subset like **index.htm**." msgstr "" "Beachten Sie, dass die Verzeichnisrekursion alle Dateien in diesem " "Verzeichnis liest, nicht nur eine Untermenge wie bspw. **index.htm**." # type: SH #: ../../src/man/linkchecker.rst:461 msgid "NOTES" msgstr "BEMERKUNGEN" # type: Plain text #: ../../src/man/linkchecker.rst:463 msgid "" "URLs on the commandline starting with **ftp.** are treated like " "**ftp://ftp.**, URLs starting with **www.** are treated like " "**http://www.**. You can also give local files as arguments. If you have " "your system configured to automatically establish a connection to the " "internet (e.g. with diald), it will connect when checking links not " "pointing to your local host. Use the :option:`--ignore-url` option to " "prevent this." msgstr "" "URLs von der Kommandozeile die mit **ftp.** beginnen werden wie " "**ftp://ftp.** behandelt, URLs die mit **www.** beginnen wie " "**http://www.**. Sie können auch lokale Dateien angeben. Falls sich Ihr " "System automatisch mit dem Internet verbindet (z.B. mit diald), wird es " "dies tun wenn Sie Links prüfen, die nicht auf Ihren lokalen Rechner " "verweisen Benutzen Sie die Option :option:`--ignore-url`, um dies zu " "verhindern." # type: Plain text #: ../../src/man/linkchecker.rst:471 msgid "Javascript links are not supported." msgstr "Javascript Links werden nicht unterstützt." # type: Plain text #: ../../src/man/linkchecker.rst:473 msgid "" "If your platform does not support threading, LinkChecker disables it " "automatically." msgstr "" "Wenn Ihr System keine Threads unterstützt, deaktiviert diese LinkChecker " "automatisch." # type: Plain text #: ../../src/man/linkchecker.rst:476 msgid "You can supply multiple user/password pairs in a configuration file." msgstr "" "Sie können mehrere Benutzer/Passwort Paare in einer Konfigurationsdatei " "angeben." # type: SH #: ../../src/man/linkchecker.rst:479 msgid "ENVIRONMENT" msgstr "UMGEBUNG" # type: Plain text #: ../../src/man/linkchecker.rst:483 msgid "specifies default HTTP proxy server" msgstr "gibt Standard HTTP Proxy an" # type: Plain text #: ../../src/man/linkchecker.rst:487 #, fuzzy msgid "specifies default HTTPS proxy server" msgstr "gibt Standard FTP Proxy an" #: ../../src/man/linkchecker.rst:491 msgid "an alternative certificate bundle to be used with an HTTPS proxy" msgstr "" #: ../../src/man/linkchecker.rst:495 msgid "comma-separated list of domains to not contact over a proxy server" msgstr "" "kommaseparierte Liste von Domains, die nicht über einen Proxy-Server " "kontaktiert werden" #: ../../src/man/linkchecker.rst:499 msgid "specify output language" msgstr "gibt Ausgabesprache an" # type: SH #: ../../src/man/linkchecker.rst:502 msgid "RETURN VALUE" msgstr "RÜCKGABEWERT" # type: Plain text #: ../../src/man/linkchecker.rst:504 msgid "The return value is 2 when" msgstr "Der Rückgabewert ist 2 falls" # type: Plain text #: ../../src/man/linkchecker.rst:506 msgid "a program error occurred." msgstr "ein Programmfehler aufgetreten ist." # type: Plain text #: ../../src/man/linkchecker.rst:508 msgid "The return value is 1 when" msgstr "Der Rückgabewert ist 1 falls" # type: Plain text #: ../../src/man/linkchecker.rst:510 msgid "invalid links were found or" msgstr "ungültige Verknüpfungen gefunden wurden oder" # type: Plain text #: ../../src/man/linkchecker.rst:511 msgid "link warnings were found and warnings are enabled" msgstr "Warnungen gefunden wurden und Warnungen aktiviert sind" # type: Plain text #: ../../src/man/linkchecker.rst:513 msgid "Else the return value is zero." msgstr "Sonst ist der Rückgabewert Null." # type: SH #: ../../src/man/linkchecker.rst:516 msgid "LIMITATIONS" msgstr "LIMITIERUNGEN" # type: Plain text #: ../../src/man/linkchecker.rst:518 msgid "" "LinkChecker consumes memory for each queued URL to check. With thousands " "of queued URLs the amount of consumed memory can become quite large. This" " might slow down the program or even the whole system." msgstr "" "LinkChecker benutzt Hauptspeicher für jede zu prüfende URL, die in der " "Warteschlange steht. Mit tausenden solcher URLs kann die Menge des " "benutzten Hauptspeichers sehr groß werden. Dies könnte das Programm oder " "sogar das gesamte System verlangsamen." # type: SH #: ../../src/man/linkchecker.rst:523 msgid "FILES" msgstr "DATEIEN" # type: Plain text #: ../../src/man/linkchecker.rst:525 #, fuzzy msgid "" "**$XDG_CONFIG_HOME/linkchecker/linkcheckerrc** - default configuration " "file" msgstr "**~/.linkchecker/linkcheckerrc** - Standardkonfigurationsdatei" # type: Plain text #: ../../src/man/linkchecker.rst:527 #, fuzzy msgid "" "**$XDG_DATA_HOME/linkchecker/failures** - default failures logger output " "filename" msgstr "" "**~/.linkchecker/failures** - Standard Dateiname der failures Logger " "Ausgabe" # type: Plain text #: ../../src/man/linkchecker.rst:529 msgid "**linkchecker-out.**\\ *TYPE* - default logger file output name" msgstr "**linkchecker-out.**\\ *TYP* - Standard Dateiname der Logausgabe" # type: SH #: ../../src/man/linkchecker.rst:532 ../../src/man/linkcheckerrc.rst:632 msgid "SEE ALSO" msgstr "SIEHE AUCH" # type: TH #: ../../src/man/linkchecker.rst:534 msgid ":manpage:`linkcheckerrc(5)`" msgstr ":manpage:`linkcheckerrc(5)`" # type: Plain text #: ../../src/man/linkchecker.rst:536 msgid "" "https://docs.python.org/library/codecs.html#standard-encodings - valid " "output encodings" msgstr "" "https://docs.python.org/library/codecs.html#standard-encodings - gültige " "Ausgabe Enkodierungen" # type: Plain text #: ../../src/man/linkchecker.rst:539 msgid "" "https://docs.python.org/howto/regex.html - regular expression " "documentation" msgstr "" "https://docs.python.org/howto/regex.html - Dokumentation zu regulären " "Ausdrücken" # type: TH #: ../../src/man/linkcheckerrc.rst:4 msgid "linkcheckerrc" msgstr "linkcheckerrc" #: ../../src/man/linkcheckerrc.rst:9 msgid "" "**linkcheckerrc** is the configuration file for LinkChecker. The file is " "written in an INI-style format. The default file location is " "**$XDG_CONFIG_HOME/linkchecker/linkcheckerrc** or else " "**~/.config/linkchecker/linkcheckerrc** on Unix, " "**%HOMEPATH%\\\\.config\\\\linkchecker\\\\linkcheckerrc** on Windows " "systems." msgstr "" # type: SH #: ../../src/man/linkcheckerrc.rst:16 msgid "SETTINGS" msgstr "EIGENSCHAFTEN" # type: SS #: ../../src/man/linkcheckerrc.rst:19 msgid "checking" msgstr "checking" # type: TP #: ../../src/man/linkcheckerrc.rst:23 msgid "**cookiefile=**\\ *filename*" msgstr "**cookiefile=**\\ *Dateiname*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:22 msgid "" "Read a file with initial cookie data. The cookie data format is explained" " in :manpage:`linkchecker(1)`. Command line option: " ":option:`--cookiefile`" msgstr "" "Lese eine Datei mit Cookie-Daten. Das Cookie Datenformat wird in " ":manpage:`linkchecker(1)` erklärt. Kommandozeilenoption: " ":option:`--cookiefile`" #: ../../src/man/linkcheckerrc.rst:27 msgid "**debugmemory=**\\ [**0**\\ \\|\\ **1**]" msgstr "**debugmemory=**\\ [**0**\\ \\|\\ **1**]" #: ../../src/man/linkcheckerrc.rst:26 msgid "" "Write memory allocation statistics to a file on exit, requires " ":pypi:`meliae`. The default is not to write the file. Command line " "option: none" msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:34 msgid "**localwebroot=**\\ *STRING*" msgstr "**localwebroot=**\\ *STRING*" #: ../../src/man/linkcheckerrc.rst:30 msgid "" "When checking absolute URLs inside local files, the given root directory " "is used as base URL. Note that the given directory must have URL syntax, " "so it must use a slash to join directories instead of a backslash. And " "the given directory must end with a slash. Command line option: none" msgstr "" "Beachten Sie dass das angegebene Verzeichnis in URL-Syntax sein muss, " "d.h. es muss einen normalen statt einen umgekehrten Schrägstrich zum " "Aneinanderfügen von Verzeichnissen benutzen. Und das angegebene " "Verzeichnis muss mit einem Schrägstrich enden. Kommandozeilenoption: none" # type: TP #: ../../src/man/linkcheckerrc.rst:38 msgid "**recursionlevel=**\\ *NUMBER*" msgstr "**recursionlevel=**\\ *NUMMER*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:37 msgid "" "Check recursively all links up to given depth. A negative depth will " "enable infinite recursion. Default depth is infinite. Command line " "option: :option:`--recursion-level`" msgstr "" "Prüfe rekursiv alle URLs bis zu der angegebenen Tiefe. Eine negative " "Tiefe bewirkt unendliche Rekursion. Standard Tiefe ist unendlich. " "Kommandozeilenoption: :option:`--recursion-level`" # type: TP #: ../../src/man/linkcheckerrc.rst:42 msgid "**threads=**\\ *NUMBER*" msgstr "**threads=**\\ *NUMMER*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:41 msgid "" "Generate no more than the given number of threads. Default number of " "threads is 10. To disable threading specify a non-positive number. " "Command line option: :option:`--threads`" msgstr "" "Generiere nicht mehr als die angegebene Anzahl von Threads. Die " "Standardanzahl von Threads ist 10. Um Threads zu deaktivieren, geben Sie " "eine nicht positive Nummer an. Kommandozeilenoption: :option:`--threads`" # type: TP #: ../../src/man/linkcheckerrc.rst:46 msgid "**timeout=**\\ *NUMBER*" msgstr "**timeout=**\\ *NUMMER*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:45 msgid "" "Set the timeout for connection attempts in seconds. The default timeout " "is 60 seconds. Command line option: :option:`--timeout`" msgstr "" "Setze den Timeout für TCP-Verbindungen in Sekunden. Der Standard Timeout " "ist 60 Sekunden. Kommandozeilenoption: :option:`--timeout`" # type: TP #: ../../src/man/linkcheckerrc.rst:51 msgid "**aborttimeout=**\\ *NUMBER*" msgstr "**aborttimeout=**\\ *NUMMER*" #: ../../src/man/linkcheckerrc.rst:49 msgid "" "Time to wait for checks to finish after the user aborts the first time " "(with Ctrl-C or the abort button). The default abort timeout is 300 " "seconds. Command line option: none" msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:56 msgid "**useragent=**\\ *STRING*" msgstr "**useragent=**\\ *STRING*" #: ../../src/man/linkcheckerrc.rst:54 msgid "" "Specify the User-Agent string to send to the HTTP server, for example " "\"Mozilla/4.0\". The default is \"LinkChecker/X.Y\" where X.Y is the " "current version of LinkChecker. Command line option: :option:`--user-" "agent`" msgstr "" "Gibt den User-Agent an, der zu HTTP-Servern geschickt wird, z.B. " "\"Mozilla/4.0\". Der Standard ist \"LinkChecker/X.Y\", wobei X.Y die " "aktuelle Version von LinkChecker ist. Kommandozeilenoption: :option" ":`--user-agent`" #: ../../src/man/linkcheckerrc.rst:62 msgid "**sslverify=**\\ [**0**\\ \\|\\ **1**\\ \\|\\ *filename*]" msgstr "**sslverify=**\\ [**0**\\ \\|\\ **1**\\ \\|\\ *filename*]" #: ../../src/man/linkcheckerrc.rst:59 msgid "" "If set to zero disables SSL certificate checking. If set to one (the " "default) enables SSL certificate checking with the provided CA " "certificate file. If a filename is specified, it will be used as the " "certificate file. Command line option: none" msgstr "" "Falls der Wert Null ist werden SSL Zertifikate nicht überprüft. Falls er " "auf Eins gesetzt wird (der Standard) werden SSL Zertifikate mit der " "gelieferten CA Zertifikatsdatei geprüft. Falls ein Dateiname angegeben " "ist wird dieser zur Prüfung verwendet. Kommandozeilenoption: none" # type: TP #: ../../src/man/linkcheckerrc.rst:68 msgid "**maxrunseconds=**\\ *NUMBER*" msgstr "**maxrunseconds=**\\ *NUMMER*" #: ../../src/man/linkcheckerrc.rst:65 msgid "" "Stop checking new URLs after the given number of seconds. Same as if the " "user stops (by hitting Ctrl-C) after the given number of seconds. The " "default is not to stop until all URLs are checked. Command line option: " "none" msgstr "" "Hört nach der angegebenen Anzahl von Sekunden auf, neue URLs zu prüfen. " "Dies ist dasselbe als wenn der Benutzer nach der gegebenen Anzahl von " "Sekunden stoppt (durch Drücken von Strg-C). Kommandozeilenoption: none" #: ../../src/man/linkcheckerrc.rst:74 msgid "**maxfilesizedownload=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:71 msgid "" "Files larger than NUMBER bytes will be ignored, without downloading " "anything if accessed over http and an accurate Content-Length header was " "returned. No more than this amount of a file will be downloaded. The " "default is 5242880 (5 MB). Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:78 msgid "**maxfilesizeparse=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:77 msgid "" "Files larger than NUMBER bytes will not be parsed for links. The default " "is 1048576 (1 MB). Command line option: none" msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:83 msgid "**maxnumurls=**\\ *NUMBER*" msgstr "**maxnumurls=**\\ *NUMMER*" #: ../../src/man/linkcheckerrc.rst:81 msgid "" "Maximum number of URLs to check. New URLs will not be queued after the " "given number of URLs is checked. The default is to queue and check all " "URLs. Command line option: none" msgstr "" "Maximale Anzahl von URLs die geprüft werden. Neue URLs werden nicht " "angenommen nachdem die angegebene Anzahl von URLs geprüft wurde. " "Kommandozeilenoption: none" # type: TP #: ../../src/man/linkcheckerrc.rst:91 msgid "**maxrequestspersecond=**\\ *NUMBER*" msgstr "**maxrequestspersecond=**\\ *NUMMER*" #: ../../src/man/linkcheckerrc.rst:86 msgid "" "Limit the maximum number of HTTP requests per second to one host. The " "average number of requests per second is approximately one third of the " "maximum. Values less than 1 and at least 0.001 can be used. To use values" " greater than 10, the HTTP server must return a **LinkChecker** response " "header. The default is 10. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:96 msgid "**robotstxt=**\\ [**0**\\ \\|\\ **1**]" msgstr "**robotstxt=**\\ [**0**\\ \\|\\ **1**]" #: ../../src/man/linkcheckerrc.rst:94 msgid "" "When using http, fetch robots.txt, and confirm whether each URL should be" " accessed before checking. The default is to use robots.txt files. " "Command line option: :option:`--no-robots`" msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:99 msgid "**allowedschemes=**\\ *NAME*\\ [**,**\\ *NAME*...]" msgstr "**allowedschemes=**\\ *NAME*\\ [**,**\\ *NAME*...]" #: ../../src/man/linkcheckerrc.rst:99 msgid "Allowed URL schemes as comma-separated list. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:104 msgid "**resultcachesize=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:102 msgid "" "Set the result cache size. The default is 100 000 URLs. Command line " "option: none" msgstr "" # type: SS #: ../../src/man/linkcheckerrc.rst:107 msgid "filtering" msgstr "filtering" #: ../../src/man/linkcheckerrc.rst:110 msgid "**ignore=**\\ *REGEX* (`MULTILINE`_)" msgstr "**ignore=**\\ *REGEX* (`MULTILINE`_)" # type: Plain text #: ../../src/man/linkcheckerrc.rst:110 msgid "" "Only check syntax of URLs matching the given regular expressions. Command" " line option: :option:`--ignore-url`" msgstr "" "Prüfe lediglich die Syntax von URLs, welche dem angegebenen regulären " "Ausdruck entsprechen. Kommandozeilenoption: :option:`--ignore-url`" # type: TP #: ../../src/man/linkcheckerrc.rst:114 msgid "**ignorewarnings=**\\ *NAME*\\ [**,**\\ *NAME*...]" msgstr "**ignorewarnings=**\\ *NAME*\\ [**,**\\ *NAME*...]" # type: Plain text #: ../../src/man/linkcheckerrc.rst:113 #, fuzzy msgid "" "Ignore the comma-separated list of warnings. See `WARNINGS`_ for the list" " of supported warnings. Messages are logged as information. Command line " "option: none" msgstr "" "Ignoriere die kommagetrennte Liste von Warnungen. Siehe `WARNINGS`_ für " "die Liste von erkannten Warnungen. Kommandozeilenoption: none" #: ../../src/man/linkcheckerrc.rst:130 #, fuzzy msgid "**ignorewarningsforurls=**\\ *URL_REGEX* [*NAME_REGEX*] (`MULTILINE`_)" msgstr "**ignore=**\\ *REGEX* (`MULTILINE`_)" #: ../../src/man/linkcheckerrc.rst:117 msgid "" "Specify regular expressions to ignore warnings for matching URLs, one per" " line. On each line, you can specify a second regular expression, " "ensuring that only the warnings with names matching the second expression" " will be ignored for that URL. If the second expression is omitted, all " "warnings are ignored for that URL." msgstr "" # type: Plain text #: ../../src/man/linkcheckerrc.rst:125 #, fuzzy msgid "" "Default is to not ignore any warnings. See `WARNINGS`_ for the list of " "supported warnings. Messages are logged as information. Command line " "option: none" msgstr "" "Ignoriere die kommagetrennte Liste von Warnungen. Siehe `WARNINGS`_ für " "die Liste von erkannten Warnungen. Kommandozeilenoption: none" # type: SH #: ../../src/man/linkcheckerrc.rst:130 #, fuzzy msgid "Example:" msgstr "BEISPIEL" # type: TP #: ../../src/man/linkcheckerrc.rst:140 msgid "**internlinks=**\\ *REGEX*" msgstr "**internlinks=**\\ *REGEX*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:139 msgid "" "Regular expression to add more URLs recognized as internal links. Default" " is that URLs given on the command line are internal. Command line " "option: none" msgstr "" "Regulärer Ausdruck, um mehr URLs als interne Verknüpfungen hinzuzufügen. " "Standard ist dass URLs der Kommandozeile als intern gelten. " "Kommandozeilenoption: none" #: ../../src/man/linkcheckerrc.rst:144 msgid "**nofollow=**\\ *REGEX* (`MULTILINE`_)" msgstr "**nofollow=**\\ *REGEX* (`MULTILINE`_)" # type: Plain text #: ../../src/man/linkcheckerrc.rst:143 msgid "" "Check but do not recurse into URLs matching the given regular " "expressions. Command line option: :option:`--no-follow-url`" msgstr "" "Prüfe URLs die auf den regulären Ausdruck zutreffen, aber führe keine " "Rekursion durch. Kommandozeilenoption: :option:`--no-follow-url`" #: ../../src/man/linkcheckerrc.rst:148 msgid "**checkextern=**\\ [**0**\\ \\|\\ **1**]" msgstr "**checkextern=**\\ [**0**\\ \\|\\ **1**]" #: ../../src/man/linkcheckerrc.rst:147 msgid "" "Check external links. Default is to check internal links only. Command " "line option: :option:`--check-extern`" msgstr "" # type: SS #: ../../src/man/linkcheckerrc.rst:151 msgid "authentication" msgstr "authentication" #: ../../src/man/linkcheckerrc.rst:164 msgid "**entry=**\\ *REGEX* *USER* [*PASS*] (`MULTILINE`_)" msgstr "**entry=**\\ *REGEX* *BENUTZER* [*PASSWORT*] (`MULTILINE`_)" #: ../../src/man/linkcheckerrc.rst:154 msgid "" "Provide individual username/password pairs for different links. In " "addition to a single login page specified with **loginurl** multiple FTP " "and HTTP (Basic Authentication) links are supported. Entries are a triple" " (URL regex, username, password) or a tuple (URL regex, username), where " "the entries are separated by whitespace. The password is optional and if " "missing it has to be entered at the commandline. If the regular " "expression matches the checked URL, the given username/password pair is " "used for authentication. The command line options :option:`-u` and " ":option:`-p` match every link and therefore override the entries given " "here. The first match wins. Command line option: :option:`-u`, " ":option:`-p`" msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:171 msgid "**loginurl=**\\ *URL*" msgstr "**loginurl=**\\ *URL*" #: ../../src/man/linkcheckerrc.rst:167 msgid "" "The URL of a login page to be visited before link checking. The page is " "expected to contain an HTML form to collect credentials and submit them " "to the address in its action attribute using an HTTP POST request. The " "name attributes of the input elements of the form and the values to be " "submitted need to be available (see **entry** for an explanation of " "username and password values)." msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:173 msgid "**loginuserfield=**\\ *STRING*" msgstr "**loginuserfield=**\\ *STRING*" #: ../../src/man/linkcheckerrc.rst:174 msgid "The name attribute of the username input element. Default: **login**." msgstr "Der Name für das Benutzer CGI-Feld. Der Standardname ist **login**." # type: TP #: ../../src/man/linkcheckerrc.rst:175 msgid "**loginpasswordfield=**\\ *STRING*" msgstr "**loginpasswordfield=**\\ *STRING*" #: ../../src/man/linkcheckerrc.rst:176 msgid "The name attribute of the password input element. Default: **password**." msgstr "Der Name für das Passwort CGI-Feld. Der Standardname ist **password**." # type: TP #: ../../src/man/linkcheckerrc.rst:181 msgid "**loginextrafields=**\\ *NAME*\\ **:**\\ *VALUE* (`MULTILINE`_)" msgstr "**loginextrafields=**\\ *NAME*\\ **:**\\ *WERT* (`MULTILINE`_)" #: ../../src/man/linkcheckerrc.rst:178 msgid "" "Optionally the name attributes of any additional input elements and the " "values to populate them with. Note that these are submitted without " "checking whether matching input elements exist in the HTML form." msgstr "" # type: SS #: ../../src/man/linkcheckerrc.rst:184 msgid "output" msgstr "output" # type: TP #: ../../src/man/linkcheckerrc.rst:195 msgid "**fileoutput=**\\ *TYPE*\\ [**,**\\ *TYPE*...]" msgstr "**fileoutput=**\\ *TYPE*\\ [**,**\\ *TYPE*...]" #: ../../src/man/linkcheckerrc.rst:190 #, fuzzy msgid "" "Output to a file **linkchecker-out.**\\ *TYPE*, or " "**$XDG_DATA_HOME/linkchecker/failures** for the **failures** output type." " Valid file output types are **text**, **html**, **sql**, **csv**, " "**gml**, **dot**, **xml**, **none** or **failures**. Default is no file " "output. The various output types are documented below. Note that you can " "suppress all console output with **output=none**. Command line option: " ":option:`--file-output`" msgstr "" "Ausgabe in Datei **linkchecker-out.**\\ *TYP*, " "**$HOME/.linkchecker/failures** für **failures** Ausgabe. Gültige " "Ausgabearten sind **text**, **html**, **sql**, **csv**, **gml**, **dot**," " **xml**, **none**> oder **failures** Standard ist keine Dateiausgabe. " "Die verschiedenen Ausgabearten sind unten dokumentiert. Bemerke, dass man" " alle Konsolenausgaben mit **output=none** unterdrücken kann. " "Kommandozeilenoption: :option:`--file-output`" #: ../../src/man/linkcheckerrc.rst:203 msgid "**log=**\\ *TYPE*\\ [**/**\\ *ENCODING*]" msgstr "**log=**\\ *TYPE*\\ [**/**\\ *ENCODING*]" #: ../../src/man/linkcheckerrc.rst:198 #, fuzzy msgid "" "Specify the console output type as **text**, **html**, **sql**, **csv**, " "**gml**, **dot**, **xml**, **none** or **failures**. Default type is " "**text**. The various output types are documented below. The *ENCODING* " "specifies the output encoding, the default is that of your locale. Valid " "encodings are listed at https://docs.python.org/library/codecs.html" "#standard-encodings. Command line option: :option:`--output`" msgstr "" "Gib Ausgabetyp als **text**, **html**, **sql**, **csv**, **gml**, " "**dot**, **xml**, **none** oder **failures** an. Stadard Typ ist " "**text**. Die verschiedenen Ausgabetypen sind unten dokumentiert. Das " "*ENCODING* gibt die Ausgabekodierung an. Der Standard ist das der lokalen" " Spracheinstellung. Gültige Enkodierungen sind aufgelistet unter " "https://docs.python.org/library/codecs.html#standard-encodings. " "Kommandozeilenoption: :option:`--output`" #: ../../src/man/linkcheckerrc.rst:207 msgid "**verbose=**\\ [**0**\\ \\|\\ **1**]" msgstr "**verbose=**\\ [**0**\\ \\|\\ **1**]" # type: Plain text #: ../../src/man/linkcheckerrc.rst:206 #, fuzzy msgid "" "If set log all checked URLs once, overriding **warnings**. Default is to " "log only errors and warnings. Command line option: :option:`--verbose`" msgstr "" "Falls gesetzt, gebe alle geprüften URLs einmal aus. Standard ist es, nur " "fehlerhafte URLs und Warnungen auszugeben. Kommandozeilenoption: " ":option:`--verbose`" #: ../../src/man/linkcheckerrc.rst:210 msgid "**warnings=**\\ [**0**\\ \\|\\ **1**]" msgstr "**warnings=**\\ [**0**\\ \\|\\ **1**]" # type: Plain text #: ../../src/man/linkcheckerrc.rst:210 msgid "" "If set log warnings. Default is to log warnings. Command line option: " ":option:`--no-warnings`" msgstr "" "Falls gesetzt, gebe keine Warnungen aus. Standard ist die Ausgabe von " "Warnungen. Kommandozeilenoption: :option:`--verbose`" #: ../../src/man/linkcheckerrc.rst:219 msgid "**ignoreerrors=**\\ *URL_REGEX* [*MESSAGE_REGEX*] (`MULTILINE`_)" msgstr "" #: ../../src/man/linkcheckerrc.rst:213 msgid "" "Specify regular expressions to ignore errors for matching URLs, one per " "line. A second regular expression can be specified per line to only " "ignore matching error messages per corresponding URL. If the second " "expression is omitted, all errors are ignored. In contrast to filtering_," " this happens *after* checking, which allows checking URLs despite " "certain expected and tolerable errors. Default is to not ignore any " "errors. Example:" msgstr "" #: ../../src/man/linkcheckerrc.rst:234 msgid "**status=**\\ [**0**\\ \\|\\ **1**]" msgstr "**status=**\\ [**0**\\ \\|\\ **1**]" # type: Plain text #: ../../src/man/linkcheckerrc.rst:233 #, fuzzy msgid "" "Control printing URL checker status messages. Default is 1. Command line " "option: :option:`--no-status`" msgstr "" "Kontrolle der Statusmeldungen. Standard ist 1. Kommandozeilenoption: " ":option:`--no-status`" # type: TP #: ../../src/man/linkcheckerrc.rst:243 msgid "**debug=**\\ *STRING*\\ [**,**\\ *STRING*...]" msgstr "**debug=**\\ *STRING*\\ [**,**\\ *STRING*...]" #: ../../src/man/linkcheckerrc.rst:240 msgid "" "Print debugging output for the given logger. Available debug loggers are " "**cmdline**, **checking**, **cache**, **plugin** and **all**. **all** is " "an alias for all available loggers. Command line option: " ":option:`--debug`" msgstr "" #: ../../src/man/linkcheckerrc.rst:252 msgid "**quiet=**\\ [**0**\\ \\|\\ **1**]" msgstr "**quiet=**\\ [**0**\\ \\|\\ **1**]" # type: Plain text #: ../../src/man/linkcheckerrc.rst:249 #, fuzzy msgid "" "If set, operate quiet. An alias for **log=none** that also hides " "application information messages. This is only useful with " "**fileoutput**, else no results will be output. Command line option: " ":option:`--quiet`" msgstr "" "Falls gesetzt, erfolgt keine Ausgabe. Ein Alias für **log=none**. Dies " "ist nur in Verbindung mit **fileoutput** nützlich. Kommandozeilenoption: " ":option:`--verbose`" # type: TP #: ../../src/man/linkcheckerrc.rst:258 msgid "text" msgstr "text" # type: TP #: ../../src/man/linkcheckerrc.rst:262 ../../src/man/linkcheckerrc.rst:310 #: ../../src/man/linkcheckerrc.rst:320 ../../src/man/linkcheckerrc.rst:330 #: ../../src/man/linkcheckerrc.rst:348 ../../src/man/linkcheckerrc.rst:362 #: ../../src/man/linkcheckerrc.rst:386 ../../src/man/linkcheckerrc.rst:394 #: ../../src/man/linkcheckerrc.rst:404 ../../src/man/linkcheckerrc.rst:414 msgid "**filename=**\\ *STRING*" msgstr "**filename=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:261 msgid "" "Specify output filename for text logging. Default filename is " "**linkchecker-out.txt**. Command line option: :option:`--file-output`" msgstr "" "Gebe Dateiname für Textausgabe an. Standard Dateiname ist **linkchecker-" "out.txt**. Kommandozeilenoption: :option:`--file-output`" # type: TP #: ../../src/man/linkcheckerrc.rst:266 ../../src/man/linkcheckerrc.rst:312 #: ../../src/man/linkcheckerrc.rst:322 ../../src/man/linkcheckerrc.rst:332 #: ../../src/man/linkcheckerrc.rst:350 ../../src/man/linkcheckerrc.rst:364 #: ../../src/man/linkcheckerrc.rst:396 ../../src/man/linkcheckerrc.rst:406 #: ../../src/man/linkcheckerrc.rst:416 msgid "**parts=**\\ *STRING*" msgstr "**parts=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:265 msgid "" "Comma-separated list of parts that have to be logged. See `LOGGER PARTS`_" " below. Command line option: none" msgstr "" "Kommagetrennte Liste von Teilen, die ausgegeben werden sollen. Siehe " "`LOGGER PARTS`_ weiter unten. Kommandozeilenoption: none" # type: TP #: ../../src/man/linkcheckerrc.rst:270 ../../src/man/linkcheckerrc.rst:315 #: ../../src/man/linkcheckerrc.rst:325 ../../src/man/linkcheckerrc.rst:334 #: ../../src/man/linkcheckerrc.rst:352 ../../src/man/linkcheckerrc.rst:366 #: ../../src/man/linkcheckerrc.rst:389 ../../src/man/linkcheckerrc.rst:399 #: ../../src/man/linkcheckerrc.rst:409 ../../src/man/linkcheckerrc.rst:418 msgid "**encoding=**\\ *STRING*" msgstr "**encoding=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:269 #, fuzzy msgid "" "Valid encodings are listed in https://docs.python.org/library/codecs.html" "#standard-encodings. Default encoding is the system default locale " "encoding." msgstr "" "Gültige Enkodierungen sind aufgelistet unter " "https://docs.python.org/library/codecs.html#standard-encodings. Die " "Standardenkodierung ist **iso-8859-15**." # type: TP #: ../../src/man/linkcheckerrc.rst:274 #, fuzzy msgid "**wraplength=**\\ *NUMBER*" msgstr "**threads=**\\ *NUMMER*" #: ../../src/man/linkcheckerrc.rst:273 msgid "" "The number of characters at which to wrap each message line. The default " "is 65. Command line option: none" msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:282 msgid "*color\\**" msgstr "*color\\**" # type: Plain text #: ../../src/man/linkcheckerrc.rst:277 msgid "" "Color settings for the various log parts, syntax is *color* or *type*\\ " "**;**\\ *color*. The *type* can be **bold**, **light**, **blink**, " "**invert**. The *color* can be **default**, **black**, **red**, " "**green**, **yellow**, **blue**, **purple**, **cyan**, **white**, " "**Black**, **Red**, **Green**, **Yellow**, **Blue**, **Purple**, **Cyan**" " or **White**. Command line option: none" msgstr "" "Farbwerte für die verschiedenen Ausgabeteile. Syntax ist *color* oder " "*type*\\ **;**\\ *color*. Der *type* kann **bold**, **light**, **blink**>" " oder **invert** sein. Die *color* kann **default**, **black**, **red**," " **green**, **yellow**, **blue**, **purple**, **cyan**, **white**, " "**Black**, **Red**, **Green**, **Yellow**, **Blue**, **Purple**, **Cyan**" " oder **White** sein. Kommandozeilenoption: none" # type: TP #: ../../src/man/linkcheckerrc.rst:284 msgid "**colorparent=**\\ *STRING*" msgstr "**colorparent=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:285 msgid "Set parent color. Default is **white**." msgstr "Setze Farbe des Vaters. Standard ist **white**." # type: TP #: ../../src/man/linkcheckerrc.rst:286 msgid "**colorurl=**\\ *STRING*" msgstr "**colorurl=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:287 msgid "Set URL color. Default is **default**." msgstr "Setze URL Farbe. Standard ist **default**." # type: TP #: ../../src/man/linkcheckerrc.rst:288 msgid "**colorname=**\\ *STRING*" msgstr "**colorname=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:289 msgid "Set name color. Default is **default**." msgstr "Setze Namensfarbe. Standard ist **default**." # type: TP #: ../../src/man/linkcheckerrc.rst:290 msgid "**colorreal=**\\ *STRING*" msgstr "**colorreal=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:291 msgid "Set real URL color. Default is **cyan**." msgstr "Setze Farbe für tatsächliche URL. Default ist **cyan**." # type: TP #: ../../src/man/linkcheckerrc.rst:292 msgid "**colorbase=**\\ *STRING*" msgstr "**colorbase=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:293 msgid "Set base URL color. Default is **purple**." msgstr "Setzt Basisurl Farbe. Standard ist **purple**." # type: TP #: ../../src/man/linkcheckerrc.rst:294 msgid "**colorvalid=**\\ *STRING*" msgstr "**colorvalid=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:295 msgid "Set valid color. Default is **bold;green**." msgstr "Setze gültige Farbe. Standard ist **bold;green**." # type: TP #: ../../src/man/linkcheckerrc.rst:296 msgid "**colorinvalid=**\\ *STRING*" msgstr "**colorinvalid=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:297 msgid "Set invalid color. Default is **bold;red**." msgstr "Setze ungültige Farbe. Standard ist **bold;red**." # type: TP #: ../../src/man/linkcheckerrc.rst:298 msgid "**colorinfo=**\\ *STRING*" msgstr "**colorinfo=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:299 msgid "Set info color. Default is **default**." msgstr "Setzt Informationsfarbe. Standard ist **default**." # type: TP #: ../../src/man/linkcheckerrc.rst:300 msgid "**colorwarning=**\\ *STRING*" msgstr "**colorwarning=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:301 msgid "Set warning color. Default is **bold;yellow**." msgstr "Setze Warnfarbe. Standard ist **bold;yellow**." # type: TP #: ../../src/man/linkcheckerrc.rst:302 msgid "**colordltime=**\\ *STRING*" msgstr "**colordltime=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:303 msgid "Set download time color. Default is **default**." msgstr "Setze Downloadzeitfarbe. Standard ist **default**." # type: TP #: ../../src/man/linkcheckerrc.rst:305 msgid "**colorreset=**\\ *STRING*" msgstr "**colorreset=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:305 msgid "Set reset color. Default is **default**." msgstr "Setze Reset Farbe. Standard ist **default**." # type: SS #: ../../src/man/linkcheckerrc.rst:308 msgid "gml" msgstr "gml" # type: Plain text #: ../../src/man/linkcheckerrc.rst:311 ../../src/man/linkcheckerrc.rst:313 #: ../../src/man/linkcheckerrc.rst:315 ../../src/man/linkcheckerrc.rst:321 #: ../../src/man/linkcheckerrc.rst:323 ../../src/man/linkcheckerrc.rst:325 #: ../../src/man/linkcheckerrc.rst:331 ../../src/man/linkcheckerrc.rst:333 #: ../../src/man/linkcheckerrc.rst:335 ../../src/man/linkcheckerrc.rst:349 #: ../../src/man/linkcheckerrc.rst:351 ../../src/man/linkcheckerrc.rst:353 #: ../../src/man/linkcheckerrc.rst:363 ../../src/man/linkcheckerrc.rst:365 #: ../../src/man/linkcheckerrc.rst:367 ../../src/man/linkcheckerrc.rst:387 #: ../../src/man/linkcheckerrc.rst:389 ../../src/man/linkcheckerrc.rst:395 #: ../../src/man/linkcheckerrc.rst:397 ../../src/man/linkcheckerrc.rst:399 #: ../../src/man/linkcheckerrc.rst:405 ../../src/man/linkcheckerrc.rst:407 #: ../../src/man/linkcheckerrc.rst:409 ../../src/man/linkcheckerrc.rst:415 #: ../../src/man/linkcheckerrc.rst:417 ../../src/man/linkcheckerrc.rst:419 msgid "See :ref:`[text] ` section above." msgstr "Siehe :ref:`[text] ` Sektion weiter oben." # type: SS #: ../../src/man/linkcheckerrc.rst:318 msgid "dot" msgstr "dot" # type: SS #: ../../src/man/linkcheckerrc.rst:328 msgid "csv" msgstr "csv" # type: TP #: ../../src/man/linkcheckerrc.rst:336 ../../src/man/linkcheckerrc.rst:357 msgid "**separator=**\\ *CHAR*" msgstr "**separator=**\\ *CHAR*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:337 #, fuzzy msgid "Set CSV separator. Default is a semicolon (**;**)." msgstr "Setze SQL Kommandotrennzeichen. Standard ist ein Strichpunkt (**;**)." # type: TP #: ../../src/man/linkcheckerrc.rst:338 msgid "**quotechar=**\\ *CHAR*" msgstr "**quotechar=**\\ *CHAR*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:339 msgid "Set CSV quote character. Default is a double quote (**\"**)." msgstr "" "Setze CSV Quotezeichen. Standard ist das doppelte Anführungszeichen " "(**\"**)." #: ../../src/man/linkcheckerrc.rst:343 msgid "**dialect=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:341 msgid "" "Controls the output formatting. See " "https://docs.python.org/3/library/csv.html#csv.Dialect. Default is " "**excel**." msgstr "" # type: SS #: ../../src/man/linkcheckerrc.rst:346 msgid "sql" msgstr "sql" # type: TP #: ../../src/man/linkcheckerrc.rst:354 msgid "**dbname=**\\ *STRING*" msgstr "**dbname=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:355 msgid "Set database name to store into. Default is **linksdb**." msgstr "Setze Datenbankname zum Speichern. Standard ist **linksdb**." # type: Plain text #: ../../src/man/linkcheckerrc.rst:357 msgid "Set SQL command separator character. Default is a semicolon (**;**)." msgstr "Setze SQL Kommandotrennzeichen. Standard ist ein Strichpunkt (**;**)." # type: TP #: ../../src/man/linkcheckerrc.rst:360 msgid "html" msgstr "html" # type: TP #: ../../src/man/linkcheckerrc.rst:368 msgid "**colorbackground=**\\ *COLOR*" msgstr "**colorbackground=**\\ *COLOR*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:369 msgid "Set HTML background color. Default is **#fff7e5**." msgstr "Setze HTML Hintergrundfarbe. Standard ist **#fff7e5**." # type: TP #: ../../src/man/linkcheckerrc.rst:370 msgid "**colorurl=**" msgstr "**colorurl=**" # type: Plain text #: ../../src/man/linkcheckerrc.rst:371 msgid "Set HTML URL color. Default is **#dcd5cf**." msgstr "Setze HTML URL Farbe. Standard ist **#dcd5cf**." # type: TP #: ../../src/man/linkcheckerrc.rst:372 msgid "**colorborder=**" msgstr "**colorborder=**" # type: Plain text #: ../../src/man/linkcheckerrc.rst:373 msgid "Set HTML border color. Default is **#000000**." msgstr "Setze HTML Rahmenfarbe. Standard ist **#000000**." # type: TP #: ../../src/man/linkcheckerrc.rst:374 msgid "**colorlink=**" msgstr "**colorlink=**" # type: Plain text #: ../../src/man/linkcheckerrc.rst:375 msgid "Set HTML link color. Default is **#191c83**." msgstr "Setze HTML Verknüpfungsfarbe. Standard ist **#191c83**." # type: TP #: ../../src/man/linkcheckerrc.rst:376 msgid "**colorwarning=**" msgstr "**colorwarning=**" # type: Plain text #: ../../src/man/linkcheckerrc.rst:377 msgid "Set HTML warning color. Default is **#e0954e**." msgstr "Setze HTML Warnfarbe. Standard ist **#e0954e**." # type: TP #: ../../src/man/linkcheckerrc.rst:378 msgid "**colorerror=**" msgstr "**colorerror=**" # type: Plain text #: ../../src/man/linkcheckerrc.rst:379 msgid "Set HTML error color. Default is **#db4930**." msgstr "Setze HTML Fehlerfarbe. Standard ist **#db4930**." # type: TP #: ../../src/man/linkcheckerrc.rst:381 msgid "**colorok=**" msgstr "**colorok=**" # type: Plain text #: ../../src/man/linkcheckerrc.rst:381 msgid "Set HTML valid color. Default is **#3ba557**." msgstr "Setze HTML Gültigkeitsfarbe. Standard ist **#3ba557**." #: ../../src/man/linkcheckerrc.rst:384 msgid "failures" msgstr "failures" # type: SS #: ../../src/man/linkcheckerrc.rst:392 msgid "xml" msgstr "xml" # type: TP #: ../../src/man/linkcheckerrc.rst:402 msgid "gxml" msgstr "gxml" #: ../../src/man/linkcheckerrc.rst:412 msgid "sitemap" msgstr "sitemap" # type: TP #: ../../src/man/linkcheckerrc.rst:421 msgid "**priority=**\\ *FLOAT*" msgstr "**priority=**\\ *NUMMER*" #: ../../src/man/linkcheckerrc.rst:421 msgid "" "A number between 0.0 and 1.0 determining the priority. The default " "priority for the first URL is 1.0, for all child URLs 0.5." msgstr "" "Eine Nummer zwischen 0.0 und 1.0, welche die Priorität festlegt. Die " "Standardpriorität für die erste URL ist 1.0, für alle Kind-URLs ist sie " "0.5." #: ../../src/man/linkcheckerrc.rst:424 msgid "" "**frequency=**\\ [**always**\\ \\|\\ **hourly**\\ \\|\\ **daily**\\ \\|\\" " **weekly**\\ \\|\\ **monthly**\\ \\|\\ **yearly**\\ \\|\\ **never**]" msgstr "" "**frequency=**\\ [**always**\\ \\|\\ **hourly**\\ \\|\\ **daily**\\ \\|\\" " **weekly**\\ \\|\\ **monthly**\\ \\|\\ **yearly**\\ \\|\\ **never**]" #: ../../src/man/linkcheckerrc.rst:424 #, fuzzy msgid "How frequently pages are changing. Default is **daily**." msgstr "Die Häufigkeit mit der Seiten sich ändern." # type: SH #: ../../src/man/linkcheckerrc.rst:427 msgid "LOGGER PARTS" msgstr "AUSGABE PARTS" #: ../../src/man/linkcheckerrc.rst:429 msgid "**all**" msgstr "**all**" #: ../../src/man/linkcheckerrc.rst:430 msgid "for all parts" msgstr "" #: ../../src/man/linkcheckerrc.rst:431 msgid "**id**" msgstr "**id**" #: ../../src/man/linkcheckerrc.rst:432 msgid "a unique ID for each logentry" msgstr "" #: ../../src/man/linkcheckerrc.rst:433 msgid "**realurl**" msgstr "**realurl**" #: ../../src/man/linkcheckerrc.rst:434 msgid "the full url link" msgstr "" #: ../../src/man/linkcheckerrc.rst:435 msgid "**result**" msgstr "**result**" #: ../../src/man/linkcheckerrc.rst:436 msgid "valid or invalid, with messages" msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:437 msgid "**extern**" msgstr "**extern**" #: ../../src/man/linkcheckerrc.rst:438 msgid "1 or 0, only in some logger types reported" msgstr "" #: ../../src/man/linkcheckerrc.rst:439 msgid "**base**" msgstr "**base**" #: ../../src/man/linkcheckerrc.rst:440 msgid "base href=..." msgstr "base href=..." #: ../../src/man/linkcheckerrc.rst:441 msgid "**name**" msgstr "**name**" #: ../../src/man/linkcheckerrc.rst:442 msgid "name and \"name\"" msgstr "name and \"name\"" #: ../../src/man/linkcheckerrc.rst:443 msgid "**parenturl**" msgstr "**parenturl**" #: ../../src/man/linkcheckerrc.rst:444 msgid "if any" msgstr "" #: ../../src/man/linkcheckerrc.rst:445 msgid "**info**" msgstr "**info**" #: ../../src/man/linkcheckerrc.rst:446 msgid "some additional info, e.g. FTP welcome messages" msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:447 msgid "**warning**" msgstr "**warning**" # type: TP #: ../../src/man/linkcheckerrc.rst:448 msgid "warnings" msgstr "" #: ../../src/man/linkcheckerrc.rst:449 msgid "**dltime**" msgstr "**dltime**" #: ../../src/man/linkcheckerrc.rst:450 msgid "download time" msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:451 msgid "**checktime**" msgstr "**checktime**" # type: TP #: ../../src/man/linkcheckerrc.rst:452 msgid "check time" msgstr "" #: ../../src/man/linkcheckerrc.rst:453 msgid "**url**" msgstr "**url**" #: ../../src/man/linkcheckerrc.rst:454 msgid "the original url name, can be relative" msgstr "" #: ../../src/man/linkcheckerrc.rst:455 msgid "**intro**" msgstr "**intro**" #: ../../src/man/linkcheckerrc.rst:456 msgid "the blurb at the beginning, \"starting at ...\"" msgstr "" #: ../../src/man/linkcheckerrc.rst:458 msgid "**outro**" msgstr "**outro**" #: ../../src/man/linkcheckerrc.rst:458 msgid "the blurb at the end, \"found x errors ...\"" msgstr "" # type: SH #: ../../src/man/linkcheckerrc.rst:461 msgid "MULTILINE" msgstr "MULTILINE" # type: Plain text #: ../../src/man/linkcheckerrc.rst:463 msgid "" "Some option values can span multiple lines. Each line has to be indented " "for that to work. Lines starting with a hash (**#**) will be ignored, " "though they must still be indented." msgstr "" "Einige Optionen können mehrere Zeilen lang sein. Jede Zeile muss dafür " "eingerückt werden. Zeilen die mit einer Raute (**#**) beginnen werden " "ignoriert, müssen aber eingerückt sein." # type: SH #: ../../src/man/linkcheckerrc.rst:476 msgid "EXAMPLE" msgstr "BEISPIEL" #: ../../src/man/linkcheckerrc.rst:492 msgid "" "All plugins have a separate section. If the section appears in the " "configuration file the plugin is enabled. Some plugins read extra options" " in their section." msgstr "" # type: SS #: ../../src/man/linkcheckerrc.rst:497 msgid "AnchorCheck" msgstr "AnchorCheck" #: ../../src/man/linkcheckerrc.rst:499 msgid "" "Checks validity of HTML anchors. When checking local files, URLs with " "anchors that link to directories e.g. \"example/#anchor\" are not " "supported. There is no such limitation when using http(s)." msgstr "" #: ../../src/man/linkcheckerrc.rst:504 msgid "LocationInfo" msgstr "LocationInfo" #: ../../src/man/linkcheckerrc.rst:506 msgid "" "Adds the country and if possible city name of the URL host as info. Needs" " GeoIP or pygeoip and a local country or city lookup DB installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:510 msgid "RegexCheck" msgstr "RegexCheck" # type: Plain text #: ../../src/man/linkcheckerrc.rst:512 msgid "" "Define a regular expression which prints a warning if it matches any " "content of the checked link. This applies only to valid pages, so we can " "get their content." msgstr "" "Definieren Sie einen regulären Ausdruck der eine Warnung ausgibt falls er" " auf den Inhalt einer geprüften URL zutrifft. Dies gilt nur für gültige " "Seiten deren Inhalt wir bekommen können." # type: TP #: ../../src/man/linkcheckerrc.rst:522 msgid "**warningregex=**\\ *REGEX*" msgstr "**warningregex=**\\ *REGEX*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:517 #, fuzzy msgid "" "Use this to check for pages that contain some form of error message, for " "example \"This page has moved\" or \"Oracle Application error\". *REGEX* " "should be unquoted." msgstr "" "Benutzen Sie dies, um nach Seiten zu suchen, welche bestimmte Fehler " "enthalten, zum Beispiel \"Diese Seite ist umgezogen\" oder \"Oracle " "Applikationsfehler\"." # type: Plain text #: ../../src/man/linkcheckerrc.rst:521 msgid "" "Note that multiple values can be combined in the regular expression, for " "example \"(This page has moved\\|Oracle Application error)\"." msgstr "" "Man beachte, dass mehrere Werte in dem regulären Ausdruck kombiniert " "werden können, zum Beispiel \"(Diese Seite ist umgezogen|Oracle " "Applikationsfehler)\"." #: ../../src/man/linkcheckerrc.rst:525 msgid "SslCertificateCheck" msgstr "SslCertificateCheck" #: ../../src/man/linkcheckerrc.rst:527 msgid "" "Check SSL certificate expiration date. Only internal https: links will be" " checked. A domain will only be checked once to avoid duplicate warnings." msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:532 msgid "**sslcertwarndays=**\\ *NUMBER*" msgstr "**sslcertwarndays=**\\ *NUMMER*" #: ../../src/man/linkcheckerrc.rst:532 msgid "Configures the expiration warning time in days." msgstr "" #: ../../src/man/linkcheckerrc.rst:535 msgid "HtmlSyntaxCheck" msgstr "HtmlSyntaxCheck" # type: Plain text #: ../../src/man/linkcheckerrc.rst:537 #, fuzzy msgid "" "Check the syntax of HTML pages by submitting their URLs to the online W3C" " HTML validator. If a page URL is not accessible to the validator no " "check is performed and no warning given. See " "https://validator.w3.org/docs/api.html." msgstr "" "Prüfe Syntax von HTML URLs mit dem W3C Online Validator. Siehe " "https://validator.w3.org/docs/api.html." #: ../../src/man/linkcheckerrc.rst:544 msgid "The HtmlSyntaxCheck plugin is currently broken and is disabled." msgstr "" #: ../../src/man/linkcheckerrc.rst:547 msgid "HttpHeaderInfo" msgstr "HttpHeaderInfo" #: ../../src/man/linkcheckerrc.rst:549 msgid "Print HTTP headers in URL info." msgstr "" #: ../../src/man/linkcheckerrc.rst:553 msgid "**prefixes=**\\ *prefix1*\\ [,*prefix2*]..." msgstr "**prefixes=**\\ *prefix1*\\ [,*prefix2*]..." #: ../../src/man/linkcheckerrc.rst:552 msgid "" "List of comma separated header prefixes. For example to display all HTTP " "headers that start with \"X-\"." msgstr "" #: ../../src/man/linkcheckerrc.rst:556 msgid "CssSyntaxCheck" msgstr "CssSyntaxCheck" # type: Plain text #: ../../src/man/linkcheckerrc.rst:558 #, fuzzy msgid "" "Check the syntax of CSS stylesheets by submitting their URLs to the " "online W3C CSS validator. If a stylesheet URL is not accessible to the " "validator no check is performed and no warning given. See " "https://jigsaw.w3.org/css-validator/manual.html#expert." msgstr "" "Prüfe Syntax von HTML URLs mit dem W3C Online Validator. Siehe " "https://jigsaw.w3.org/css-validator/manual.html#expert." #: ../../src/man/linkcheckerrc.rst:564 msgid "VirusCheck" msgstr "VirusCheck" #: ../../src/man/linkcheckerrc.rst:566 msgid "" "Checks the page content for virus infections with clamav. A local clamav " "daemon must be installed." msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:570 msgid "**clamavconf=**\\ *filename*" msgstr "**clamavconf=**\\ *Dateiname*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:570 msgid "Filename of **clamd.conf** config file." msgstr "Dateiname von **clamd.conf** Konfigurationsdatei." #: ../../src/man/linkcheckerrc.rst:573 msgid "PdfParser" msgstr "PdfParser" #: ../../src/man/linkcheckerrc.rst:575 msgid "" "Parse PDF files for URLs to check. Needs the :pypi:`pdfminer.six` Python " "package installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:579 msgid "WordParser" msgstr "WordParser" #: ../../src/man/linkcheckerrc.rst:581 msgid "" "Parse Word files for URLs to check. Needs the :pypi:`pywin32` Python " "extension installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:585 msgid "MarkdownCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:587 msgid "Parse Markdown files for URLs to check." msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:590 msgid "**filename_re=**\\ *REGEX*" msgstr "**filename_re=**\\ *REGEX*" #: ../../src/man/linkcheckerrc.rst:590 msgid "Regular expression matching the names of Markdown files." msgstr "" #: ../../src/man/linkcheckerrc.rst:593 msgid "WARNINGS" msgstr "WARNUNGEN" #: ../../src/man/linkcheckerrc.rst:595 #, fuzzy msgid "" "The following warnings are recognized by **ignorewarnings** and " "**ignorewarningsforurls**:" msgstr "" "Die folgenden Warnungen werden vom Konfigurationseintrag 'ignorewarnings'" " erkannt:" #: ../../src/man/linkcheckerrc.rst:598 msgid "**file-anchorcheck-directory**" msgstr "" #: ../../src/man/linkcheckerrc.rst:599 msgid "A local directory with an anchor, not supported by AnchorCheck." msgstr "" #: ../../src/man/linkcheckerrc.rst:600 msgid "**file-missing-slash**" msgstr "**file-missing-slash**" #: ../../src/man/linkcheckerrc.rst:601 msgid "The file: URL is missing a trailing slash." msgstr "Der file: URL fehlt ein abschließender Schrägstrich." #: ../../src/man/linkcheckerrc.rst:602 msgid "**file-system-path**" msgstr "**file-system-path**" #: ../../src/man/linkcheckerrc.rst:603 msgid "The file: path is not the same as the system specific path." msgstr "Der file: Pfad ist nicht derselbe wie der Systempfad." #: ../../src/man/linkcheckerrc.rst:604 msgid "**ftp-missing-slash**" msgstr "**ftp-missing-slash**" #: ../../src/man/linkcheckerrc.rst:605 msgid "The ftp: URL is missing a trailing slash." msgstr "Der ftp: URL fehlt ein abschließender Schrägstrich." # type: TP #: ../../src/man/linkcheckerrc.rst:606 msgid "**http-cookie-store-error**" msgstr "**http-cookie-store-error**" #: ../../src/man/linkcheckerrc.rst:607 msgid "An error occurred while storing a cookie." msgstr "Ein Fehler trat auf während des Speicherns eines Cookies." #: ../../src/man/linkcheckerrc.rst:608 msgid "**http-empty-content**" msgstr "**http-empty-content**" #: ../../src/man/linkcheckerrc.rst:609 msgid "The URL had no content." msgstr "Die URL besitzt keinen Inhalt." #: ../../src/man/linkcheckerrc.rst:610 msgid "**http-rate-limited**" msgstr "" #: ../../src/man/linkcheckerrc.rst:611 msgid "Too many HTTP requests." msgstr "" #: ../../src/man/linkcheckerrc.rst:612 #, fuzzy msgid "**http-redirected**" msgstr "**http-empty-content**" #: ../../src/man/linkcheckerrc.rst:613 msgid "Redirected to a different URL." msgstr "" #: ../../src/man/linkcheckerrc.rst:614 msgid "**mail-no-mx-host**" msgstr "**mail-no-mx-host**" #: ../../src/man/linkcheckerrc.rst:615 msgid "The mail MX host could not be found." msgstr "Der MX Mail-Rechner konnte nicht gefunden werden." #: ../../src/man/linkcheckerrc.rst:616 msgid "**url-content-size-zero**" msgstr "**url-content-size-zero**" #: ../../src/man/linkcheckerrc.rst:617 msgid "The URL content size is zero." msgstr "Der URL Inhaltsgrößenangabe ist Null." #: ../../src/man/linkcheckerrc.rst:618 msgid "**url-content-too-large**" msgstr "**url-content-too-large**" #: ../../src/man/linkcheckerrc.rst:619 msgid "The URL content size is too large." msgstr "Der URL Inhalt ist zu groß." #: ../../src/man/linkcheckerrc.rst:620 #, fuzzy msgid "**url-content-type-unparseable**" msgstr "**url-content-too-large**" #: ../../src/man/linkcheckerrc.rst:621 #, fuzzy msgid "The URL content type is not parseable." msgstr "Der URL Inhalt ist zu groß." #: ../../src/man/linkcheckerrc.rst:622 msgid "**url-effective-url**" msgstr "**url-effective-url**" #: ../../src/man/linkcheckerrc.rst:623 msgid "The effective URL is different from the original." msgstr "Die effektive URL unterscheidet sich vom Original." #: ../../src/man/linkcheckerrc.rst:624 msgid "**url-error-getting-content**" msgstr "**url-error-getting-content**" #: ../../src/man/linkcheckerrc.rst:625 msgid "Could not get the content of the URL." msgstr "Konnte den Inhalt der URL nicht bekommen." #: ../../src/man/linkcheckerrc.rst:626 msgid "**url-obfuscated-ip**" msgstr "**url-obfuscated-ip**" #: ../../src/man/linkcheckerrc.rst:627 msgid "The IP is obfuscated." msgstr "Die IP-Adresse ist verschleiert." #: ../../src/man/linkcheckerrc.rst:629 msgid "**url-whitespace**" msgstr "**url-whitespace**" #: ../../src/man/linkcheckerrc.rst:629 msgid "The URL contains leading or trailing whitespace." msgstr "Die URL %(url)s enthält Leerzeichen am Anfang oder Ende." # type: TH #: ../../src/man/linkcheckerrc.rst:634 msgid ":manpage:`linkchecker(1)`" msgstr ":manpage:`linkchecker(1)`" #~ msgid "HTML and CSS syntax check" #~ msgstr "HTML- und CSS-Syntaxprüfung" #~ msgid "" #~ "Define a regular expression which prints" #~ " a warning if it matches any " #~ "content of the checked link. This " #~ "applies only to valid pages, so we" #~ " can get their content. Use this " #~ "to check for pages that contain " #~ "some form of error, for example " #~ "\"This page has moved\" or \"Oracle " #~ "Application error\". Note that multiple " #~ "values can be combined in the " #~ "regular expression, for example \"(This " #~ "page has moved|Oracle Application error)\"." #~ " See section `REGULAR EXPRESSIONS`_ for " #~ "more info." #~ msgstr "" #~ "Definieren Sie einen regulären Ausdruck " #~ "der eine Warnung ausgibt falls er " #~ "auf den Inhalt einer geprüften URL " #~ "zutrifft. Dies gilt nur für gültige " #~ "Seiten deren Inhalt wir bekommen können." #~ " Benutzen Sie dies, um nach Seiten" #~ " zu suchen, welche bestimmte Fehler " #~ "enthalten, zum Beispiel \\\"Diese Seite " #~ "ist umgezogen\\\" oder \\\"Oracle " #~ "\"Applikationsfehler\\\". Man beachte, dass " #~ "mehrere Werte in dem regulären Ausdruck" #~ " kombiniert werden können, zum Beispiel " #~ "\\\"(Diese Seite ist umgezogen|Oracle " #~ "Applikationsfehler)\\\". Siehe Abschnitt `REGULAR" #~ " EXPRESSIONS`_ für weitere Infos." #~ msgid "" #~ "Time to wait for checks to finish" #~ " after the user aborts the first " #~ "time (with Ctrl-C or the abort " #~ "button). The default abort timeout is" #~ " 300 seconds. Command line option: " #~ ":option:`--timeout`" #~ msgstr "" # type: Plain text #~ msgid "Set CSV separator. Default is a comma (**,**)." #~ msgstr "Das CSV Trennzeichen. Standard ist Komma (**,**)." # type: Plain text #~ msgid "" #~ "Print debugging output for the given " #~ "logger. Available loggers are cmdline, " #~ "checking, cache, dns, plugin and all." #~ " Specifying all is an alias for " #~ "specifying all available loggers. The " #~ "option can be given multiple times " #~ "to debug with more than one " #~ "logger. For accurate results, threading " #~ "will be disabled during debug runs." #~ msgstr "" #~ "Gebe Testmeldungen aus für den " #~ "angegebenen Logger. Verfügbare Logger sind " #~ "cmdline, checking, cache, dns, plugin " #~ "und all. Die Angabe all ist ein" #~ " Synonym für alle verfügbaren Logger. " #~ "Diese Option kann mehrmals angegeben " #~ "werden, um mit mehr als einem " #~ "Logger zu testen. Um akkurate Ergebnisse" #~ " zu erzielen, werden Threads deaktiviert." #~ msgid "" #~ "**linkcheckerrc** is the configuration file" #~ " for LinkChecker. The file is written" #~ " in an INI-style format. The " #~ "default file location is " #~ "**~/.linkchecker/linkcheckerrc** on Unix, " #~ "**%HOMEPATH%\\\\.linkchecker\\\\linkcheckerrc** on Windows" #~ " systems." #~ msgstr "" #~ "**linkcheckerrc** ist die Konfigurationsdatei " #~ "für LinkChecker. Die Datei ist in " #~ "einem INI-Format geschrieben. Die " #~ "Standarddatei ist **~/.linkchecker/linkcheckerrc** " #~ "unter Unix-, " #~ "**%HOMEPATH%\\\\linkchecker\\\\linkcheckerrc** unter " #~ "Windows-Systemen." #~ msgid "" #~ "Limit the maximum number of requests " #~ "per second to one host. The " #~ "default is 10. Command line option: " #~ "none" #~ msgstr "" #~ msgid "" #~ "Provide individual username/password pairs for" #~ " different links. In addtion to a " #~ "single login page specified with " #~ "**loginurl** multiple FTP, HTTP (Basic " #~ "Authentication) and telnet links are " #~ "supported. Entries are a triple (URL " #~ "regex, username, password) or a tuple" #~ " (URL regex, username), where the " #~ "entries are separated by whitespace. The" #~ " password is optional and if missing" #~ " it has to be entered at the" #~ " commandline. If the regular expression " #~ "matches the checked URL, the given " #~ "username/password pair is used for " #~ "authentication. The command line options " #~ ":option:`-u` and :option:`-p` match every " #~ "link and therefore override the entries" #~ " given here. The first match wins." #~ " Command line option: :option:`-u`, " #~ ":option:`-p`" #~ msgstr "" # type: Plain text #~ msgid "" #~ "Print debugging output for the given " #~ "modules. Available debug modules are " #~ "**cmdline**, **checking**, **cache**, **dns**, " #~ "**thread**, **plugins** and **all**. " #~ "Specifying **all** is an alias for " #~ "specifying all available loggers. Command " #~ "line option: :option:`--debug`" #~ msgstr "" #~ "Gebe Testmeldungen aus für den " #~ "angegebenen Logger. Verfügbare Logger sind " #~ "**cmdline**, **checking**, **cache**, **dns**, " #~ "**thread**, **plugins** und **all**. Die " #~ "Angabe **all** ist ein Synonym für " #~ "alle verfügbaren Logger. Kommandozeilenoption: " #~ ":option:`--debug`" #~ msgid "Checks validity of HTML anchors." #~ msgstr "" #~ msgid "The AnchorCheck plugin is currently broken and is disabled." #~ msgstr "" #~ msgid "" #~ "Parse PDF files for URLs to check." #~ " Needs the :pypi:`pdfminer` Python package" #~ " installed." #~ msgstr "" # type: Plain text #~ msgid "" #~ "Specify an NNTP server for news: " #~ "links. Default is the environment " #~ "variable :envvar:`NNTP_SERVER`. If no host " #~ "is given, only the syntax of the" #~ " link is checked." #~ msgstr "" #~ "Gibt ein NNTP Rechner für news: " #~ "Links. Standard ist die Umgebungsvariable " #~ ":envvar:`NNTP_SERVER`. Falls kein Rechner " #~ "angegeben ist, wird lediglich auf " #~ "korrekte Syntax des Links geprüft." #~ msgid "Telnet links (**telnet:**)" #~ msgstr "Telnet links (**telnet:**)" #~ msgid "" #~ "We try to connect and if " #~ "user/password are given, login to the" #~ " given telnet server." #~ msgstr "" #~ "Versuche, zu dem angegeben Telnetrechner " #~ "zu verginden und falls Benutzer/Passwort " #~ "angegeben sind, wird versucht, sich " #~ "anzumelden." #~ msgid "NNTP links (**news:**, **snews:**, **nntp**)" #~ msgstr "NNTP links (**news:**, **snews:**, **nntp**)" #~ msgid "" #~ "We try to connect to the given " #~ "NNTP server. If a news group or" #~ " article is specified, try to request" #~ " it from the server." #~ msgstr "" #~ "Versuche, zu dem angegebenen NNTP-" #~ "Rechner eine Verbindung aufzubaucne. Falls " #~ "eine Nachrichtengruppe oder ein bestimmter " #~ "Artikel angegeben ist, wird versucht, " #~ "diese Gruppe oder diesen Artikel vom " #~ "Rechner anzufragen." # type: Plain text #~ msgid "" #~ "When checking **news:** links the given" #~ " NNTP host doesn't need to be " #~ "the same as the host of the " #~ "user browsing your pages." #~ msgstr "" #~ "Beim Prüfen von **news:** Links muß " #~ "der angegebene NNTP Rechner nicht " #~ "unbedingt derselbe wie der des Benutzers" #~ " sein." # type: Plain text #~ msgid "specifies default NNTP server" #~ msgstr "gibt Standard NNTP Server an" # type: TP #~ msgid "**nntpserver=**\\ *STRING*" #~ msgstr "**nntpserver=**\\ *STRING*" # type: Plain text #~ msgid "" #~ "Specify an NNTP server for **news:** " #~ "links. Default is the environment " #~ "variable :envvar:`NNTP_SERVER`. If no host " #~ "is given, only the syntax of the" #~ " link is checked. Command line " #~ "option: :option:`--nntp-server`" #~ msgstr "" #~ "Gibt ein NNTP Rechner für **news:** " #~ "Links. Standard ist die Umgebungsvariable " #~ ":envvar:`NNTP_SERVER`. Falls kein Rechner " #~ "angegeben ist, wird lediglich auf " #~ "korrekte Syntax des Links geprüft. " #~ "Kommandozeilenoption: :option:`--nntp-server`" #~ msgid "" #~ "Provide individual username/password pairs for" #~ " different links. In addition to a" #~ " single login page specified with " #~ "**loginurl** multiple FTP, HTTP (Basic " #~ "Authentication) and telnet links are " #~ "supported. Entries are a triple (URL " #~ "regex, username, password) or a tuple" #~ " (URL regex, username), where the " #~ "entries are separated by whitespace. The" #~ " password is optional and if missing" #~ " it has to be entered at the" #~ " commandline. If the regular expression " #~ "matches the checked URL, the given " #~ "username/password pair is used for " #~ "authentication. The command line options " #~ ":option:`-u` and :option:`-p` match every " #~ "link and therefore override the entries" #~ " given here. The first match wins." #~ " Command line option: :option:`-u`, " #~ ":option:`-p`" #~ msgstr "" #~ msgid "**nntp-no-newsgroup**" #~ msgstr "**nntp-no-newsgroup**" #~ msgid "The NNTP newsgroup could not be found." #~ msgstr "Die NNTP Nachrichtengruppe konnte nicht gefunden werden." # type: TP #~ msgid "**nntp-no-server**" #~ msgstr "**nntp-no-server**" #~ msgid "No NNTP server was found." #~ msgstr "Es wurde kein NNTP Server gefunden." #~ msgid "" #~ "Limit the maximum number of HTTP " #~ "requests per second to one host. " #~ "The average number of requests per " #~ "second is approximately one third of " #~ "the maximum. Values less than 1 " #~ "and at least 0.001 can be used." #~ " To use values greater than 10, " #~ "the HTTP server must return a " #~ "\"LinkChecker\" response header. The default" #~ " is 10. Command line option: none" #~ msgstr "" linkchecker-10.5.0/doc/i18n/locales/fr/000077500000000000000000000000001466565367000174565ustar00rootroot00000000000000linkchecker-10.5.0/doc/i18n/locales/fr/LC_MESSAGES/000077500000000000000000000000001466565367000212435ustar00rootroot00000000000000linkchecker-10.5.0/doc/i18n/locales/fr/LC_MESSAGES/man.po000066400000000000000000002230201466565367000223550ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE # Copyright (C) YEAR Free Software Foundation, Inc. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: linkchecker 3.4\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-08-05 19:32+0100\n" "POT-Creation-Date: 2020-08-05 19:38+0100\n" "Last-Translator: Yann Verley \n" "Language-Team: kde-francophone@kde.org\n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../../src/man/linkchecker.rst:4 msgid "linkchecker" msgstr "" # type: SH #: ../../src/man/linkchecker.rst:7 msgid "SYNOPSIS" msgstr "SYNOPSIS" # type: Plain text #: ../../src/man/linkchecker.rst:9 #, fuzzy msgid "**linkchecker** [*options*] [*file-or-url*]..." msgstr "B [ I ] [ I ]" # type: SH #: ../../src/man/linkchecker.rst:12 ../../src/man/linkcheckerrc.rst:7 msgid "DESCRIPTION" msgstr "DESCRIPTION" #: ../../src/man/linkchecker.rst:14 msgid "LinkChecker features" msgstr "" #: ../../src/man/linkchecker.rst:16 msgid "recursive and multithreaded checking" msgstr "" #: ../../src/man/linkchecker.rst:17 msgid "" "output in colored or normal text, HTML, SQL, CSV, XML or a sitemap graph in " "different formats" msgstr "" #: ../../src/man/linkchecker.rst:19 msgid "" "support for HTTP/1.1, HTTPS, FTP, mailto:, news:, nntp:, Telnet and local " "file links" msgstr "" #: ../../src/man/linkchecker.rst:21 msgid "restriction of link checking with URL filters" msgstr "" #: ../../src/man/linkchecker.rst:22 msgid "proxy support" msgstr "" #: ../../src/man/linkchecker.rst:23 msgid "username/password authorization for HTTP, FTP and Telnet" msgstr "" #: ../../src/man/linkchecker.rst:24 msgid "support for robots.txt exclusion protocol" msgstr "" #: ../../src/man/linkchecker.rst:25 msgid "support for Cookies" msgstr "" #: ../../src/man/linkchecker.rst:26 msgid "support for HTML5" msgstr "" #: ../../src/man/linkchecker.rst:27 msgid "HTML and CSS syntax check" msgstr "" #: ../../src/man/linkchecker.rst:28 msgid "Antivirus check" msgstr "" #: ../../src/man/linkchecker.rst:29 msgid "a command line and web interface" msgstr "" # type: SH #: ../../src/man/linkchecker.rst:32 msgid "EXAMPLES" msgstr "EXEMPLES" #: ../../src/man/linkchecker.rst:34 msgid "The most common use checks the given domain recursively:" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:40 #, fuzzy msgid "" "Beware that this checks the whole site which can have thousands of URLs. Use " "the :option:`-r` option to restrict the recursion depth." msgstr "" "Faites attention, car ceci vérifie le site en entier, celui-ci pouvant avoir " "plusieurs centaines de milliers d'URL. Utilisez l'option B<-r> pour " "restreindre la profondeur de la récursion." #: ../../src/man/linkchecker.rst:43 msgid "" "Don't check URLs with **/secret** in its name. All other links are checked " "as usual:" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:50 #, fuzzy msgid "Checking a local HTML file on Unix:" msgstr "" "Pour vérifier un fichier HTML local sur Unix :\n" " B\n" # type: Plain text #: ../../src/man/linkchecker.rst:56 #, fuzzy msgid "Checking a local HTML file on Windows:" msgstr "" "Pour vérifier un fichier HTML local sur Windows :\n" " B\n" # type: Plain text #: ../../src/man/linkchecker.rst:62 #, fuzzy msgid "" "You can skip the **http://** url part if the domain starts with **www.**:" msgstr "" "Vous pouvez ne pas mettre la partie B de l'URL si le nom de domaine " "commence par B :\n" " B\n" # type: Plain text #: ../../src/man/linkchecker.rst:69 #, fuzzy msgid "" "You can skip the **ftp://** url part if the domain starts with **ftp.**:" msgstr "" "Vous pouvez ne pas mettre la partie B de l'URL si le nom de domaine " "commence par B :\n" " B\n" #: ../../src/man/linkchecker.rst:75 msgid "Generate a sitemap graph and convert it with the graphviz dot utility:" msgstr "" # type: SH #: ../../src/man/linkchecker.rst:82 msgid "OPTIONS" msgstr "OPTIONS" # type: SS #: ../../src/man/linkchecker.rst:85 msgid "General options" msgstr "Options générales" # type: Plain text #: ../../src/man/linkchecker.rst:89 #, fuzzy msgid "" "Use FILENAME as configuration file. By default LinkChecker uses ~/." "linkchecker/linkcheckerrc." msgstr "" "Utiliser I comme fichier de configuration. LinkChecker recherche " "d'abord B puis B<~/.linkchecker/" "linkcheckerrc>." # type: Plain text #: ../../src/man/linkchecker.rst:94 msgid "Help me! Print usage information for this program." msgstr "Afficher des informations sur l'utilisation du programme." #: ../../src/man/linkchecker.rst:98 msgid "Read list of white-space separated URLs to check from stdin." msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:102 #, fuzzy msgid "" "Generate no more than the given number of threads. Default number of threads " "is 10. To disable threading specify a non-positive number." msgstr "" "Permettre de ne pas avoir plus de I threads. Le nombre de threads est " "fixé par défaut à 10.Pour désactiver le multithreading, spécifier un nombre " "non positif." # type: Plain text #: ../../src/man/linkchecker.rst:107 msgid "Print version and exit." msgstr "Afficher la version et quitter." # type: Plain text #: ../../src/man/linkchecker.rst:111 #, fuzzy msgid "Print available check plugins and exit." msgstr "Afficher la version et quitter." # type: SS #: ../../src/man/linkchecker.rst:114 msgid "Output options" msgstr "Options de sortie" # type: Plain text #: ../../src/man/linkchecker.rst:118 #, fuzzy msgid "" "Print debugging output for the given logger. Available loggers are cmdline, " "checking, cache, dns, plugin and all. Specifying all is an alias for " "specifying all available loggers. The option can be given multiple times to " "debug with more than one logger. For accurate results, threading will be " "disabled during debug runs." msgstr "" "Afficher les sorties de débogage pour l'enregistreur de journal I. " "Les enregistreurs disponibles sont : B, B, B, " "B and B. B est un alias pour indiquer que l'on veut tous les " "enregistreurs disponibles. Cette option peut être donnée plusieurs fois pour " "déboguer avec plus d'un enregistreur de journal. Le multithreading est " "désactivé pendant une exécution en mode debug afin de garantir la précision " "des résultats." # type: Plain text #: ../../src/man/linkchecker.rst:127 #, fuzzy msgid "" "Output to a file linkchecker-out.TYPE, $HOME/.linkchecker/blacklist for " "blacklist output, or FILENAME if specified. The ENCODING specifies the " "output encoding, the default is that of your locale. Valid encodings are " "listed at https://docs.python.org/library/codecs.html#standard-encodings. " "The FILENAME and ENCODING parts of the none output type will be ignored, " "else if the file already exists, it will be overwritten. You can specify " "this option more than once. Valid file output TYPEs are text, html, sql, " "csv, gml, dot, xml, sitemap, none or blacklist. Default is no file output. " "The various output types are documented below. Note that you can suppress " "all console output with the option :option:`-o` *none*." msgstr "" "Enregistrer la sortie dans un fichier BI, B<$HOME/." "linkchecker/blacklist> pour la sortie B, ou dans I " "si spécifié. I permet de spécifier l'encodage de sortie, la valeur " "par défaut étant B. Les encodages valides sont disponibles sur " "B.La partie I du type " "de sortie B est ignorée, sinon, si le fichier existe déjà, il sera " "écrasé.Vous pouvez spécifier l'option plusieurs fois. Les types de sortie " "valides pour les fichiers sont B, B, B, B, B, " "B, B, B ou B.Par défaut, il n'y a pas de fichier " "de sortie. Les différents types de sortie sont documentés ci-dessous. Il " "faut noter que vous pouvez supprimer toutes les sorties console avec " "l'option B<-o none>." # type: Plain text #: ../../src/man/linkchecker.rst:143 msgid "Do not print check status messages." msgstr "Ne pas afficher les messages d'état de la vérification." # type: Plain text #: ../../src/man/linkchecker.rst:147 msgid "Don't log warnings. Default is to log warnings." msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:151 #, fuzzy msgid "" "Specify output type as text, html, sql, csv, gml, dot, xml, sitemap, none or " "blacklist. Default type is text. The various output types are documented " "below. The ENCODING specifies the output encoding, the default is that of " "your locale. Valid encodings are listed at https://docs.python.org/library/" "codecs.html#standard-encodings." msgstr "" "Spécifier le type de sortie. Les types possibles sont B, B, " "B, B, B, B, B, B ou B. Le type par " "défaut est B. Les différents types de sortie sont documentés ci-" "dessous. I permet de spécifier l'encodage de sortie, la valeur par " "défaut étant B. Les encodages valides sont disponibles sur " "B." # type: Plain text #: ../../src/man/linkchecker.rst:161 #, fuzzy msgid "" "Quiet operation, an alias for :option:`-o` *none*. This is only useful with :" "option:`-F`." msgstr "" "Exécution silencieuse, c'est un alias pour B<-o none>. Cette option n'est " "utile qu'avec B<-F>." # type: Plain text #: ../../src/man/linkchecker.rst:166 #, fuzzy msgid "Log all checked URLs. Default is to log only errors and warnings." msgstr "" "Journaliser toutes les URL vérifiées (implique B<-w>). Par défaut, seules " "les URL invalides sont mises dans le journal." #: ../../src/man/linkchecker.rst:170 msgid "" "Define a regular expression which prints a warning if it matches any content " "of the checked link. This applies only to valid pages, so we can get their " "content. Use this to check for pages that contain some form of error, for " "example \"This page has moved\" or \"Oracle Application error\". Note that " "multiple values can be combined in the regular expression, for example " "\"(This page has moved|Oracle Application error)\". See section `REGULAR " "EXPRESSIONS`_ for more info." msgstr "" # type: SS #: ../../src/man/linkchecker.rst:180 msgid "Checking options" msgstr "Options de vérification" # type: Plain text #: ../../src/man/linkchecker.rst:184 msgid "" "Read a file with initial cookie data. The cookie data format is explained " "below." msgstr "" #: ../../src/man/linkchecker.rst:189 msgid "Check external URLs." msgstr "" #: ../../src/man/linkchecker.rst:193 msgid "" "URLs matching the given regular expression will be ignored and not checked. " "This option can be given multiple times. See section `REGULAR EXPRESSIONS`_ " "for more info." msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:200 #, fuzzy msgid "" "Specify an NNTP server for news: links. Default is the environment variable :" "envvar:`NNTP_SERVER`. If no host is given, only the syntax of the link is " "checked." msgstr "" "Spécifier un serveur NNTP pour les liens « news: ». Par défaut, la variable " "d'environnement B est utilisée. Si aucun hôte n'est donné, " "LinkChecker n'effectue qu'une vérification de la syntaxe du lien." #: ../../src/man/linkchecker.rst:206 msgid "" "Check but do not recurse into URLs matching the given regular expression. " "This option can be given multiple times. See section `REGULAR EXPRESSIONS`_ " "for more info." msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:213 #, fuzzy msgid "" "Read a password from console and use it for HTTP and FTP authorization. For " "FTP the default password is anonymous@. For HTTP there is no default " "password. See also :option:`-u`." msgstr "" "Essayer le mot de passe I pour l'autorisation HTTP et FTP. Pour FTP, le " "mot de passe par défaut est B. Voir aussi B<-u>." # type: Plain text #: ../../src/man/linkchecker.rst:219 #, fuzzy msgid "" "Check recursively all links up to given depth. A negative depth will enable " "infinite recursion. Default depth is infinite." msgstr "" "Vérifier récursivement tous les liens jusqu'à une Idonnée. Une " "profondeur négative permet d'avoir une récursion infinie. Par défaut, la " "récursion est infinie." # type: Plain text #: ../../src/man/linkchecker.rst:224 #, fuzzy msgid "" "Set the timeout for connection attempts in seconds. The default timeout is " "60 seconds." msgstr "" "Préciser le délai d'expiration pour les attentes de connexion en secondes. " "Le délai par défaut est de 30 secondes." # type: Plain text #: ../../src/man/linkchecker.rst:229 #, fuzzy msgid "" "Try the given username for HTTP and FTP authorization. For FTP the default " "username is anonymous. For HTTP there is no default username. See also :" "option:`-p`." msgstr "" "Essayer le nom d'utilisateur I pour l'autorisation HTTP et FTP. Pour " "FTP, le nom d'utilisateur par défaut est B. Voir aussi B<-p>." #: ../../src/man/linkchecker.rst:235 msgid "" "Specify the User-Agent string to send to the HTTP server, for example " "\"Mozilla/4.0\". The default is \"LinkChecker/X.Y\" where X.Y is the current " "version of LinkChecker." msgstr "" # type: SH #: ../../src/man/linkchecker.rst:240 msgid "CONFIGURATION FILES" msgstr "" #: ../../src/man/linkchecker.rst:242 msgid "" "Configuration files can specify all options above. They can also specify " "some options that cannot be set on the command line. See :manpage:" "`linkcheckerrc(5)` for more info." msgstr "" # type: SH #: ../../src/man/linkchecker.rst:247 msgid "OUTPUT TYPES" msgstr "OUTPUT TYPES" #: ../../src/man/linkchecker.rst:249 msgid "" "Note that by default only errors and warnings are logged. You should use the " "option :option:`--verbose` to get the complete URL list, especially when " "outputting a sitemap graph format." msgstr "" #: ../../src/man/linkchecker.rst:253 msgid "**text**" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:254 msgid "Standard text logger, logging URLs in keyword: argument fashion." msgstr "" "Sortie texte standard, journaliser les URL dans des mots clés : mode " "argument." #: ../../src/man/linkchecker.rst:257 msgid "**html**" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:256 #, fuzzy msgid "" "Log URLs in keyword: argument fashion, formatted as HTML. Additionally has " "links to the referenced pages. Invalid URLs have HTML and CSS syntax check " "links appended." msgstr "" "Journaliser les URL dans des mots clés : mode argument, formaté en HTML. " "Contient aussi des liens vers les pages référencées. Les URL invalides ont " "aussi en plus une vérification syntaxique des liens HTML et CSS." #: ../../src/man/linkchecker.rst:259 msgid "**csv**" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:260 msgid "Log check result in CSV format with one URL per line." msgstr "" "Journaliser le résultat de la vérification au format CSV avec une URL par " "ligne." #: ../../src/man/linkchecker.rst:262 msgid "**gml**" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:262 #, fuzzy msgid "Log parent-child relations between linked URLs as a GML sitemap graph." msgstr "" "Journaliser les relations fils/père entre les URL liées dans un graphe GML. " "Vous devez utiliser l'option B<--verbose> pour avoir un graphe complet." #: ../../src/man/linkchecker.rst:265 msgid "**dot**" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:265 #, fuzzy msgid "Log parent-child relations between linked URLs as a DOT sitemap graph." msgstr "" "Journaliser les relations fils/père entre les URL liées dans un graphe DOT. " "Vous devez utiliser l'option B<--verbose> pour avoir un graphe complet." #: ../../src/man/linkchecker.rst:267 msgid "**gxml**" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:268 #, fuzzy msgid "Log check result as a GraphXML sitemap graph." msgstr "" "Journaliser le résultat de la vérification dans un fichier au format XML." #: ../../src/man/linkchecker.rst:269 msgid "**xml**" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:270 #, fuzzy msgid "Log check result as machine-readable XML." msgstr "" "Journaliser le résultat de la vérification dans un fichier au format XML." #: ../../src/man/linkchecker.rst:272 msgid "**sitemap**" msgstr "" #: ../../src/man/linkchecker.rst:272 msgid "" "Log check result as an XML sitemap whose protocol is documented at https://" "www.sitemaps.org/protocol.html." msgstr "" #: ../../src/man/linkchecker.rst:275 msgid "**sql**" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:275 msgid "" "Log check result as SQL script with INSERT commands. An example script to " "create the initial SQL table is included as create.sql." msgstr "" "Journaliser le résultat dans un script SQL avec des commandes INSERT. Un " "script d'exemple montrant la création de la table SQL initiale est inclus : " "create.sql." # type: TP #: ../../src/man/linkchecker.rst:279 #, fuzzy msgid "**blacklist**" msgstr "B" # type: Plain text #: ../../src/man/linkchecker.rst:278 #, fuzzy msgid "" "Suitable for cron jobs. Logs the check result into a file **~/.linkchecker/" "blacklist** which only contains entries with invalid URLs and the number of " "times they have failed." msgstr "" "Approprié pour les tâches cron. Journaliser le résultat de la vérification " "dans un fichier B<~/.linkchecker/blacklist> qui ne contient que les entrées " "avec des URL invalides et le nombre de fois qu'elles ont échoué." #: ../../src/man/linkchecker.rst:282 msgid "**none**" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:282 #, fuzzy msgid "Logs nothing. Suitable for debugging or checking the exit code." msgstr "Ne rien journaliser du tout. Approprié pour les scripts." # type: SH #: ../../src/man/linkchecker.rst:285 msgid "REGULAR EXPRESSIONS" msgstr "" #: ../../src/man/linkchecker.rst:287 msgid "" "LinkChecker accepts Python regular expressions. See https://docs.python.org/" "howto/regex.html for an introduction. An addition is that a leading " "exclamation mark negates the regular expression." msgstr "" # type: SH #: ../../src/man/linkchecker.rst:293 msgid "COOKIE FILES" msgstr "" #: ../../src/man/linkchecker.rst:295 msgid "" "A cookie file contains standard HTTP header (RFC 2616) data with the " "following possible names:" msgstr "" #: ../../src/man/linkchecker.rst:298 msgid "**Host** (required)" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:299 msgid "Sets the domain the cookies are valid for." msgstr "" #: ../../src/man/linkchecker.rst:300 msgid "**Path** (optional)" msgstr "" #: ../../src/man/linkchecker.rst:301 msgid "Gives the path the cookies are value for; default path is **/**." msgstr "" #: ../../src/man/linkchecker.rst:303 msgid "**Set-cookie** (required)" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:303 msgid "Set cookie name/value. Can be given more than once." msgstr "" #: ../../src/man/linkchecker.rst:305 msgid "" "Multiple entries are separated by a blank line. The example below will send " "two cookies to all URLs starting with **http://example.com/hello/** and one " "to all URLs starting with **https://example.org/**:" msgstr "" # type: SH #: ../../src/man/linkchecker.rst:323 msgid "PROXY SUPPORT" msgstr "" #: ../../src/man/linkchecker.rst:325 msgid "" "To use a proxy on Unix or Windows set the :envvar:`http_proxy`, :envvar:" "`https_proxy` or :envvar:`ftp_proxy` environment variables to the proxy URL. " "The URL should be of the form **http://**\\ [*user*\\ **:**\\ *pass*\\ " "**@**]\\ *host*\\ [**:**\\ *port*]. LinkChecker also detects manual proxy " "settings of Internet Explorer under Windows systems, and GNOME or KDE on " "Linux systems. On a Mac use the Internet Config to select a proxy. You can " "also set a comma-separated domain list in the :envvar:`no_proxy` environment " "variables to ignore any proxy settings for these domains." msgstr "" #: ../../src/man/linkchecker.rst:335 msgid "Setting a HTTP proxy on Unix for example looks like this:" msgstr "" #: ../../src/man/linkchecker.rst:341 msgid "Proxy authentication is also supported:" msgstr "" #: ../../src/man/linkchecker.rst:347 msgid "Setting a proxy on the Windows command prompt:" msgstr "" #: ../../src/man/linkchecker.rst:354 msgid "PERFORMED CHECKS" msgstr "" #: ../../src/man/linkchecker.rst:356 msgid "" "All URLs have to pass a preliminary syntax test. Minor quoting mistakes will " "issue a warning, all other invalid syntax issues are errors. After the " "syntax check passes, the URL is queued for connection checking. All " "connection check types are described below." msgstr "" #: ../../src/man/linkchecker.rst:367 msgid "HTTP links (**http:**, **https:**)" msgstr "" #: ../../src/man/linkchecker.rst:362 msgid "" "After connecting to the given HTTP server the given path or query is " "requested. All redirections are followed, and if user/password is given it " "will be used as authorization when necessary. All final HTTP status codes " "other than 2xx are errors." msgstr "" #: ../../src/man/linkchecker.rst:367 msgid "HTML page contents are checked for recursion." msgstr "" #: ../../src/man/linkchecker.rst:374 msgid "Local files (**file:**)" msgstr "" #: ../../src/man/linkchecker.rst:370 msgid "" "A regular, readable file that can be opened is valid. A readable directory " "is also valid. All other files, for example device files, unreadable or non-" "existing files are errors." msgstr "" #: ../../src/man/linkchecker.rst:374 msgid "HTML or other parseable file contents are checked for recursion." msgstr "" #: ../../src/man/linkchecker.rst:389 msgid "Mail links (**mailto:**)" msgstr "" #: ../../src/man/linkchecker.rst:377 msgid "" "A mailto: link eventually resolves to a list of email addresses. If one " "address fails, the whole list will fail. For each mail address we check the " "following things:" msgstr "" #: ../../src/man/linkchecker.rst:381 msgid "Check the adress syntax, both of the part before and after the @ sign." msgstr "" #: ../../src/man/linkchecker.rst:383 msgid "Look up the MX DNS records. If we found no MX record, print an error." msgstr "" #: ../../src/man/linkchecker.rst:385 msgid "" "Check if one of the mail hosts accept an SMTP connection. Check hosts with " "higher priority first. If no host accepts SMTP, we print a warning." msgstr "" #: ../../src/man/linkchecker.rst:388 msgid "" "Try to verify the address with the VRFY command. If we got an answer, print " "the verified address as an info." msgstr "" #: ../../src/man/linkchecker.rst:398 msgid "FTP links (**ftp:**)" msgstr "" #: ../../src/man/linkchecker.rst:392 msgid "For FTP links we do:" msgstr "" #: ../../src/man/linkchecker.rst:394 msgid "connect to the specified host" msgstr "" #: ../../src/man/linkchecker.rst:395 msgid "" "try to login with the given user and password. The default user is " "**anonymous**, the default password is **anonymous@**." msgstr "" #: ../../src/man/linkchecker.rst:397 msgid "try to change to the given directory" msgstr "" #: ../../src/man/linkchecker.rst:398 msgid "list the file with the NLST command" msgstr "" #: ../../src/man/linkchecker.rst:402 msgid "Telnet links (**telnet:**)" msgstr "" #: ../../src/man/linkchecker.rst:401 msgid "" "We try to connect and if user/password are given, login to the given telnet " "server." msgstr "" #: ../../src/man/linkchecker.rst:406 msgid "NNTP links (**news:**, **snews:**, **nntp**)" msgstr "" #: ../../src/man/linkchecker.rst:405 msgid "" "We try to connect to the given NNTP server. If a news group or article is " "specified, try to request it from the server." msgstr "" #: ../../src/man/linkchecker.rst:415 msgid "Unsupported links (**javascript:**, etc.)" msgstr "" #: ../../src/man/linkchecker.rst:409 msgid "" "An unsupported link will only print a warning. No further checking will be " "made." msgstr "" #: ../../src/man/linkchecker.rst:412 msgid "" "The complete list of recognized, but unsupported links can be found in the " "`linkcheck/checker/unknownurl.py `__ source file. The most " "prominent of them should be JavaScript links." msgstr "" #: ../../src/man/linkchecker.rst:418 ../../src/man/linkcheckerrc.rst:400 msgid "PLUGINS" msgstr "" #: ../../src/man/linkchecker.rst:420 msgid "" "There are two plugin types: connection and content plugins. Connection " "plugins are run after a successful connection to the URL host. Content " "plugins are run if the URL type has content (mailto: URLs have no content " "for example) and if the check is not forbidden (ie. by HTTP robots.txt). Use " "the option :option:`--list-plugins` for a list of plugins and their " "documentation. All plugins are enabled via the :manpage:`linkcheckerrc(5)` " "configuration file." msgstr "" #: ../../src/man/linkchecker.rst:430 msgid "RECURSION" msgstr "" #: ../../src/man/linkchecker.rst:432 msgid "" "Before descending recursively into a URL, it has to fulfill several " "conditions. They are checked in this order:" msgstr "" #: ../../src/man/linkchecker.rst:435 msgid "A URL must be valid." msgstr "" #: ../../src/man/linkchecker.rst:436 msgid "" "A URL must be parseable. This currently includes HTML files, Opera bookmarks " "files, and directories. If a file type cannot be determined (for example it " "does not have a common HTML file extension, and the content does not look " "like HTML), it is assumed to be non-parseable." msgstr "" #: ../../src/man/linkchecker.rst:440 msgid "" "The URL content must be retrievable. This is usually the case except for " "example mailto: or unknown URL types." msgstr "" #: ../../src/man/linkchecker.rst:442 msgid "" "The maximum recursion level must not be exceeded. It is configured with the :" "option:`--recursion-level` option and is unlimited per default." msgstr "" #: ../../src/man/linkchecker.rst:444 msgid "" "It must not match the ignored URL list. This is controlled with the :option:" "`--ignore-url` option." msgstr "" #: ../../src/man/linkchecker.rst:446 msgid "" "The Robots Exclusion Protocol must allow links in the URL to be followed " "recursively. This is checked by searching for a \"nofollow\" directive in " "the HTML header data." msgstr "" #: ../../src/man/linkchecker.rst:450 msgid "" "Note that the directory recursion reads all files in that directory, not " "just a subset like **index.htm**." msgstr "" # type: SH #: ../../src/man/linkchecker.rst:454 msgid "NOTES" msgstr "NOTES" # type: Plain text #: ../../src/man/linkchecker.rst:456 #, fuzzy msgid "" "URLs on the commandline starting with **ftp.** are treated like **ftp://ftp." "**, URLs starting with **www.** are treated like **http://www.**. You can " "also give local files as arguments. If you have your system configured to " "automatically establish a connection to the internet (e.g. with diald), it " "will connect when checking links not pointing to your local host. Use the :" "option:`--ignore-url` option to prevent this." msgstr "" "Si votre système est configuré pour établir automatiquement une connexion à " "internet (par exemple, avec diald), il se connectera quand les liens de " "vérification ne pointent pas sur votre système local. Utilisez les options " "B<-s> et B<-i> pour éviter cela." # type: Plain text #: ../../src/man/linkchecker.rst:464 #, fuzzy msgid "Javascript links are not supported." msgstr "Les liens javascript sont ignorés actuellement." # type: Plain text #: ../../src/man/linkchecker.rst:466 #, fuzzy msgid "" "If your platform does not support threading, LinkChecker disables it " "automatically." msgstr "" "Si votre plate-forme n'accepte pas le multithreading, LinkChecker utilise B<-" "t0>." # type: Plain text #: ../../src/man/linkchecker.rst:469 msgid "You can supply multiple user/password pairs in a configuration file." msgstr "" "Vous pouvez fournir plusieurs paires nom d'utilisateur/mot de passe dans un " "fichier de configuration." # type: Plain text #: ../../src/man/linkchecker.rst:471 #, fuzzy msgid "" "When checking **news:** links the given NNTP host doesn't need to be the " "same as the host of the user browsing your pages." msgstr "" "Pour la vérification des liens B, les liens de l'hôte NNTP donné " "n'ont pas besoin d'être les mêmes que l'hôte de l'utilisateur naviguant." # type: SH #: ../../src/man/linkchecker.rst:475 msgid "ENVIRONMENT" msgstr "ENVIRONNEMENT" # type: Plain text #: ../../src/man/linkchecker.rst:479 #, fuzzy msgid "specifies default NNTP server" msgstr "B - spécifie le serveur NNTP par défaut" # type: Plain text #: ../../src/man/linkchecker.rst:483 #, fuzzy msgid "specifies default HTTP proxy server" msgstr "B - spécifie le proxy HTTP par défaut" # type: Plain text #: ../../src/man/linkchecker.rst:487 #, fuzzy msgid "specifies default FTP proxy server" msgstr "B - spécifie le proxy FTP par défaut" #: ../../src/man/linkchecker.rst:491 msgid "comma-separated list of domains to not contact over a proxy server" msgstr "" #: ../../src/man/linkchecker.rst:495 msgid "specify output language" msgstr "" # type: SH #: ../../src/man/linkchecker.rst:498 msgid "RETURN VALUE" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:500 #, fuzzy msgid "The return value is 2 when" msgstr "Le code de retour est différent de 0 quand" # type: Plain text #: ../../src/man/linkchecker.rst:502 msgid "a program error occurred." msgstr "il y a eu une erreur dans le programme." # type: Plain text #: ../../src/man/linkchecker.rst:504 #, fuzzy msgid "The return value is 1 when" msgstr "Le code de retour est différent de 0 quand" # type: Plain text #: ../../src/man/linkchecker.rst:506 msgid "invalid links were found or" msgstr "il y a eu des liens non valides," # type: Plain text #: ../../src/man/linkchecker.rst:507 #, fuzzy msgid "link warnings were found and warnings are enabled" msgstr "" "il y a eu des avertissements sur les liens et l'option --warnings était " "positionnée," # type: Plain text #: ../../src/man/linkchecker.rst:509 #, fuzzy msgid "Else the return value is zero." msgstr "Le code de retour est différent de 0 quand" #: ../../src/man/linkchecker.rst:512 msgid "LIMITATIONS" msgstr "" #: ../../src/man/linkchecker.rst:514 msgid "" "LinkChecker consumes memory for each queued URL to check. With thousands of " "queued URLs the amount of consumed memory can become quite large. This might " "slow down the program or even the whole system." msgstr "" # type: SH #: ../../src/man/linkchecker.rst:519 msgid "FILES" msgstr "FICHIERS" # type: Plain text #: ../../src/man/linkchecker.rst:521 #, fuzzy msgid "**~/.linkchecker/linkcheckerrc** - default configuration file" msgstr "" "B, B<~/.linkchecker/linkcheckerrc> - " "fichiers de configuration par défaut" # type: Plain text #: ../../src/man/linkchecker.rst:523 #, fuzzy msgid "**~/.linkchecker/blacklist** - default blacklist logger output filename" msgstr "" "B<~/.linkchecker/blacklist> - fichier par défaut des blacklists pour la " "journalisation" # type: Plain text #: ../../src/man/linkchecker.rst:525 #, fuzzy msgid "**linkchecker-out.**\\ *TYPE* - default logger file output name" msgstr "BI - fichier par défaut pour la journalisation" # type: SH #: ../../src/man/linkchecker.rst:528 ../../src/man/linkcheckerrc.rst:520 msgid "SEE ALSO" msgstr "" #: ../../src/man/linkchecker.rst:530 msgid ":manpage:`linkcheckerrc(5)`" msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:532 #, fuzzy msgid "" "https://docs.python.org/library/codecs.html#standard-encodings - valid " "output encodings" msgstr "" "B - encodages valides de " "sortie" #: ../../src/man/linkchecker.rst:535 msgid "" "https://docs.python.org/howto/regex.html - regular expression documentation" msgstr "" #: ../../src/man/linkcheckerrc.rst:4 msgid "linkcheckerrc" msgstr "" #: ../../src/man/linkcheckerrc.rst:9 msgid "" "**linkcheckerrc** is the configuration file for LinkChecker. The file is " "written in an INI-style format. The default file location is **~/." "linkchecker/linkcheckerrc** on Unix, **%HOMEPATH%\\\\.linkchecker\\" "\\linkcheckerrc** on Windows systems." msgstr "" #: ../../src/man/linkcheckerrc.rst:15 msgid "SETTINGS" msgstr "" #: ../../src/man/linkcheckerrc.rst:18 msgid "checking" msgstr "" #: ../../src/man/linkcheckerrc.rst:22 msgid "**cookiefile=**\\ *filename*" msgstr "" #: ../../src/man/linkcheckerrc.rst:21 msgid "" "Read a file with initial cookie data. The cookie data format is explained " "in :manpage:`linkchecker(1)`. Command line option: :option:`--cookiefile`" msgstr "" #: ../../src/man/linkcheckerrc.rst:29 msgid "**localwebroot=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:25 msgid "" "When checking absolute URLs inside local files, the given root directory is " "used as base URL. Note that the given directory must have URL syntax, so it " "must use a slash to join directories instead of a backslash. And the given " "directory must end with a slash. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:34 msgid "**nntpserver=**\\ *STRING*" msgstr "" # type: Plain text #: ../../src/man/linkcheckerrc.rst:32 #, fuzzy msgid "" "Specify an NNTP server for **news:** links. Default is the environment " "variable :envvar:`NNTP_SERVER`. If no host is given, only the syntax of the " "link is checked. Command line option: :option:`--nntp-server`" msgstr "" "Spécifier un serveur NNTP pour les liens « news: ». Par défaut, la variable " "d'environnement B est utilisée. Si aucun hôte n'est donné, " "LinkChecker n'effectue qu'une vérification de la syntaxe du lien." #: ../../src/man/linkcheckerrc.rst:38 msgid "**recursionlevel=**\\ *NUMBER*" msgstr "" # type: Plain text #: ../../src/man/linkcheckerrc.rst:37 #, fuzzy msgid "" "Check recursively all links up to given depth. A negative depth will enable " "infinite recursion. Default depth is infinite. Command line option: :option:" "`--recursion-level`" msgstr "" "Vérifier récursivement tous les liens jusqu'à une Idonnée. Une " "profondeur négative permet d'avoir une récursion infinie. Par défaut, la " "récursion est infinie." #: ../../src/man/linkcheckerrc.rst:42 msgid "**threads=**\\ *NUMBER*" msgstr "" # type: Plain text #: ../../src/man/linkcheckerrc.rst:41 #, fuzzy msgid "" "Generate no more than the given number of threads. Default number of threads " "is 10. To disable threading specify a non-positive number. Command line " "option: :option:`--threads`" msgstr "" "Permettre de ne pas avoir plus de I threads. Le nombre de threads est " "fixé par défaut à 10.Pour désactiver le multithreading, spécifier un nombre " "non positif." # type: TP #: ../../src/man/linkcheckerrc.rst:46 #, fuzzy msgid "**timeout=**\\ *NUMBER*" msgstr "B<--timeout=>I" # type: Plain text #: ../../src/man/linkcheckerrc.rst:45 #, fuzzy msgid "" "Set the timeout for connection attempts in seconds. The default timeout is " "60 seconds. Command line option: :option:`--timeout`" msgstr "" "Préciser le délai d'expiration pour les attentes de connexion en secondes. " "Le délai par défaut est de 30 secondes." #: ../../src/man/linkcheckerrc.rst:51 msgid "**aborttimeout=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:49 msgid "" "Time to wait for checks to finish after the user aborts the first time (with " "Ctrl-C or the abort button). The default abort timeout is 300 seconds. " "Command line option: :option:`--timeout`" msgstr "" #: ../../src/man/linkcheckerrc.rst:56 msgid "**useragent=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:54 msgid "" "Specify the User-Agent string to send to the HTTP server, for example " "\"Mozilla/4.0\". The default is \"LinkChecker/X.Y\" where X.Y is the current " "version of LinkChecker. Command line option: :option:`--user-agent`" msgstr "" #: ../../src/man/linkcheckerrc.rst:62 msgid "**sslverify=**\\ [**0**\\ \\|\\ **1**\\ \\|\\ *filename*]" msgstr "" #: ../../src/man/linkcheckerrc.rst:59 msgid "" "If set to zero disables SSL certificate checking. If set to one (the " "default) enables SSL certificate checking with the provided CA certificate " "file. If a filename is specified, it will be used as the certificate file. " "Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:68 msgid "**maxrunseconds=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:65 msgid "" "Stop checking new URLs after the given number of seconds. Same as if the " "user stops (by hitting Ctrl-C) after the given number of seconds. The " "default is not to stop until all URLs are checked. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:73 msgid "**maxnumurls=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:71 msgid "" "Maximum number of URLs to check. New URLs will not be queued after the given " "number of URLs is checked. The default is to queue and check all URLs. " "Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:75 msgid "**maxrequestspersecond=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:76 msgid "Limit the maximum number of requests per second to one host." msgstr "" #: ../../src/man/linkcheckerrc.rst:78 msgid "**allowedschemes=**\\ *NAME*\\ [**,**\\ *NAME*...]" msgstr "" #: ../../src/man/linkcheckerrc.rst:78 msgid "Allowed URL schemes as comma-separated list." msgstr "" #: ../../src/man/linkcheckerrc.rst:81 msgid "filtering" msgstr "" #: ../../src/man/linkcheckerrc.rst:84 msgid "**ignore=**\\ *REGEX* (MULTILINE)" msgstr "" #: ../../src/man/linkcheckerrc.rst:84 msgid "" "Only check syntax of URLs matching the given regular expressions. Command " "line option: :option:`--ignore-url`" msgstr "" #: ../../src/man/linkcheckerrc.rst:88 msgid "**ignorewarnings=**\\ *NAME*\\ [**,**\\ *NAME*...]" msgstr "" #: ../../src/man/linkcheckerrc.rst:87 msgid "" "Ignore the comma-separated list of warnings. See `WARNINGS`_ for the list of " "supported warnings. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:92 msgid "**internlinks=**\\ *REGEX*" msgstr "" #: ../../src/man/linkcheckerrc.rst:91 msgid "" "Regular expression to add more URLs recognized as internal links. Default is " "that URLs given on the command line are internal. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:96 msgid "**nofollow=**\\ *REGEX* (MULTILINE)" msgstr "" #: ../../src/man/linkcheckerrc.rst:95 msgid "" "Check but do not recurse into URLs matching the given regular expressions. " "Command line option: :option:`--no-follow-url`" msgstr "" #: ../../src/man/linkcheckerrc.rst:100 msgid "**checkextern=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:99 msgid "" "Check external links. Default is to check internal links only. Command line " "option: :option:`--check-extern`" msgstr "" #: ../../src/man/linkcheckerrc.rst:103 msgid "authentication" msgstr "" #: ../../src/man/linkcheckerrc.rst:116 msgid "**entry=**\\ *REGEX* *USER* [*PASS*] (MULTILINE)" msgstr "" #: ../../src/man/linkcheckerrc.rst:106 msgid "" "Provide individual username/password pairs for different links. In addtion " "to a single login page specified with **loginurl** multiple FTP, HTTP (Basic " "Authentication) and telnet links are supported. Entries are a triple (URL " "regex, username, password) or a tuple (URL regex, username), where the " "entries are separated by whitespace. The password is optional and if missing " "it has to be entered at the commandline. If the regular expression matches " "the checked URL, the given username/password pair is used for " "authentication. The command line options :option:`-u` and :option:`-p` match " "every link and therefore override the entries given here. The first match " "wins. Command line option: :option:`-u`, :option:`-p`" msgstr "" #: ../../src/man/linkcheckerrc.rst:123 msgid "**loginurl=**\\ *URL*" msgstr "" #: ../../src/man/linkcheckerrc.rst:119 msgid "" "The URL of a login page to be visited before link checking. The page is " "expected to contain an HTML form to collect credentials and submit them to " "the address in its action attribute using an HTTP POST request. The name " "attributes of the input elements of the form and the values to be submitted " "need to be available (see **entry** for an explanation of username and " "password values)." msgstr "" #: ../../src/man/linkcheckerrc.rst:125 msgid "**loginuserfield=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:126 msgid "The name attribute of the username input element. Default: **login**." msgstr "" #: ../../src/man/linkcheckerrc.rst:127 msgid "**loginpasswordfield=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:128 msgid "" "The name attribute of the password input element. Default: **password**." msgstr "" #: ../../src/man/linkcheckerrc.rst:133 msgid "**loginextrafields=**\\ *NAME*\\ **:**\\ *VALUE* (MULTILINE)" msgstr "" #: ../../src/man/linkcheckerrc.rst:130 msgid "" "Optionally the name attributes of any additional input elements and the " "values to populate them with. Note that these are submitted without checking " "whether matching input elements exist in the HTML form." msgstr "" #: ../../src/man/linkcheckerrc.rst:136 msgid "output" msgstr "" #: ../../src/man/linkcheckerrc.rst:142 msgid "**debug=**\\ *STRING*\\ [**,**\\ *STRING*...]" msgstr "" # type: Plain text #: ../../src/man/linkcheckerrc.rst:139 #, fuzzy msgid "" "Print debugging output for the given modules. Available debug modules are " "**cmdline**, **checking**, **cache**, **dns**, **thread**, **plugins** and " "**all**. Specifying **all** is an alias for specifying all available " "loggers. Command line option: :option:`--debug`" msgstr "" "Afficher les sorties de débogage pour l'enregistreur de journal I. " "Les enregistreurs disponibles sont : B, B, B, " "B and B. B est un alias pour indiquer que l'on veut tous les " "enregistreurs disponibles. Cette option peut être donnée plusieurs fois pour " "déboguer avec plus d'un enregistreur de journal. Le multithreading est " "désactivé pendant une exécution en mode debug afin de garantir la précision " "des résultats." #: ../../src/man/linkcheckerrc.rst:150 msgid "**fileoutput=**\\ *TYPE*\\ [**,**\\ *TYPE*...]" msgstr "" #: ../../src/man/linkcheckerrc.rst:145 msgid "" "Output to a files **linkchecker-out.**\\ *TYPE*, **$HOME/.linkchecker/" "blacklist** for **blacklist** output. Valid file output types are **text**, " "**html**, **sql**, **csv**, **gml**, **dot**, **xml**, **none** or " "**blacklist** Default is no file output. The various output types are " "documented below. Note that you can suppress all console output with " "**output=none**. Command line option: :option:`--file-output`" msgstr "" #: ../../src/man/linkcheckerrc.rst:158 msgid "**log=**\\ *TYPE*\\ [**/**\\ *ENCODING*]" msgstr "" # type: Plain text #: ../../src/man/linkcheckerrc.rst:153 #, fuzzy msgid "" "Specify output type as **text**, **html**, **sql**, **csv**, **gml**, " "**dot**, **xml**, **none** or **blacklist**. Default type is **text**. The " "various output types are documented below. The *ENCODING* specifies the " "output encoding, the default is that of your locale. Valid encodings are " "listed at https://docs.python.org/library/codecs.html#standard-encodings. " "Command line option: :option:`--output`" msgstr "" "Spécifier le type de sortie. Les types possibles sont B, B, " "B, B, B, B, B, B ou B. Le type par " "défaut est B. Les différents types de sortie sont documentés ci-" "dessous. I permet de spécifier l'encodage de sortie, la valeur par " "défaut étant B. Les encodages valides sont disponibles sur " "B." #: ../../src/man/linkcheckerrc.rst:162 msgid "**quiet=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:161 msgid "" "If set, operate quiet. An alias for **log=none**. This is only useful with " "**fileoutput**. Command line option: :option:`--verbose`" msgstr "" #: ../../src/man/linkcheckerrc.rst:165 msgid "**status=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:165 msgid "" "Control printing check status messages. Default is 1. Command line option: :" "option:`--no-status`" msgstr "" #: ../../src/man/linkcheckerrc.rst:169 msgid "**verbose=**\\ [**0**\\ \\|\\ **1**]" msgstr "" # type: Plain text #: ../../src/man/linkcheckerrc.rst:168 #, fuzzy msgid "" "If set log all checked URLs once. Default is to log only errors and " "warnings. Command line option: :option:`--verbose`" msgstr "" "Journaliser toutes les URL vérifiées (implique B<-w>). Par défaut, seules " "les URL invalides sont mises dans le journal." #: ../../src/man/linkcheckerrc.rst:173 msgid "**warnings=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:172 msgid "" "If set log warnings. Default is to log warnings. Command line option: :" "option:`--no-warnings`" msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:176 #, fuzzy msgid "text" msgstr "B" #: ../../src/man/linkcheckerrc.rst:180 ../../src/man/linkcheckerrc.rst:224 #: ../../src/man/linkcheckerrc.rst:234 ../../src/man/linkcheckerrc.rst:244 #: ../../src/man/linkcheckerrc.rst:258 ../../src/man/linkcheckerrc.rst:272 #: ../../src/man/linkcheckerrc.rst:296 ../../src/man/linkcheckerrc.rst:304 #: ../../src/man/linkcheckerrc.rst:314 ../../src/man/linkcheckerrc.rst:324 msgid "**filename=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:179 msgid "" "Specify output filename for text logging. Default filename is **linkchecker-" "out.txt**. Command line option: :option:`--file-output`" msgstr "" #: ../../src/man/linkcheckerrc.rst:184 ../../src/man/linkcheckerrc.rst:226 #: ../../src/man/linkcheckerrc.rst:236 ../../src/man/linkcheckerrc.rst:246 #: ../../src/man/linkcheckerrc.rst:260 ../../src/man/linkcheckerrc.rst:274 #: ../../src/man/linkcheckerrc.rst:306 ../../src/man/linkcheckerrc.rst:316 #: ../../src/man/linkcheckerrc.rst:326 msgid "**parts=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:183 msgid "" "Comma-separated list of parts that have to be logged. See `LOGGER PARTS`_ " "below. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:188 ../../src/man/linkcheckerrc.rst:229 #: ../../src/man/linkcheckerrc.rst:239 ../../src/man/linkcheckerrc.rst:248 #: ../../src/man/linkcheckerrc.rst:262 ../../src/man/linkcheckerrc.rst:276 #: ../../src/man/linkcheckerrc.rst:299 ../../src/man/linkcheckerrc.rst:309 #: ../../src/man/linkcheckerrc.rst:319 ../../src/man/linkcheckerrc.rst:328 msgid "**encoding=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:187 msgid "" "Valid encodings are listed in https://docs.python.org/library/codecs." "html#standard-encodings. Default encoding is **iso-8859-15**." msgstr "" #: ../../src/man/linkcheckerrc.rst:196 msgid "*color\\**" msgstr "" #: ../../src/man/linkcheckerrc.rst:191 msgid "" "Color settings for the various log parts, syntax is *color* or *type*\\ **;**" "\\ *color*. The *type* can be **bold**, **light**, **blink**, **invert**. " "The *color* can be **default**, **black**, **red**, **green**, **yellow**, " "**blue**, **purple**, **cyan**, **white**, **Black**, **Red**, **Green**, " "**Yellow**, **Blue**, **Purple**, **Cyan** or **White**. Command line " "option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:198 msgid "**colorparent=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:199 msgid "Set parent color. Default is **white**." msgstr "" #: ../../src/man/linkcheckerrc.rst:200 msgid "**colorurl=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:201 msgid "Set URL color. Default is **default**." msgstr "" #: ../../src/man/linkcheckerrc.rst:202 msgid "**colorname=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:203 msgid "Set name color. Default is **default**." msgstr "" #: ../../src/man/linkcheckerrc.rst:204 msgid "**colorreal=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:205 msgid "Set real URL color. Default is **cyan**." msgstr "" #: ../../src/man/linkcheckerrc.rst:206 msgid "**colorbase=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:207 msgid "Set base URL color. Default is **purple**." msgstr "" #: ../../src/man/linkcheckerrc.rst:208 msgid "**colorvalid=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:209 msgid "Set valid color. Default is **bold;green**." msgstr "" #: ../../src/man/linkcheckerrc.rst:210 msgid "**colorinvalid=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:211 msgid "Set invalid color. Default is **bold;red**." msgstr "" #: ../../src/man/linkcheckerrc.rst:212 msgid "**colorinfo=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:213 msgid "Set info color. Default is **default**." msgstr "" #: ../../src/man/linkcheckerrc.rst:214 msgid "**colorwarning=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:215 msgid "Set warning color. Default is **bold;yellow**." msgstr "" #: ../../src/man/linkcheckerrc.rst:216 msgid "**colordltime=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:217 msgid "Set download time color. Default is **default**." msgstr "" #: ../../src/man/linkcheckerrc.rst:219 msgid "**colorreset=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:219 msgid "Set reset color. Default is **default**." msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:222 #, fuzzy msgid "gml" msgstr "B" #: ../../src/man/linkcheckerrc.rst:225 ../../src/man/linkcheckerrc.rst:227 #: ../../src/man/linkcheckerrc.rst:229 ../../src/man/linkcheckerrc.rst:235 #: ../../src/man/linkcheckerrc.rst:237 ../../src/man/linkcheckerrc.rst:239 #: ../../src/man/linkcheckerrc.rst:245 ../../src/man/linkcheckerrc.rst:247 #: ../../src/man/linkcheckerrc.rst:249 ../../src/man/linkcheckerrc.rst:259 #: ../../src/man/linkcheckerrc.rst:261 ../../src/man/linkcheckerrc.rst:263 #: ../../src/man/linkcheckerrc.rst:273 ../../src/man/linkcheckerrc.rst:275 #: ../../src/man/linkcheckerrc.rst:277 ../../src/man/linkcheckerrc.rst:297 #: ../../src/man/linkcheckerrc.rst:299 ../../src/man/linkcheckerrc.rst:305 #: ../../src/man/linkcheckerrc.rst:307 ../../src/man/linkcheckerrc.rst:309 #: ../../src/man/linkcheckerrc.rst:315 ../../src/man/linkcheckerrc.rst:317 #: ../../src/man/linkcheckerrc.rst:319 ../../src/man/linkcheckerrc.rst:325 #: ../../src/man/linkcheckerrc.rst:327 ../../src/man/linkcheckerrc.rst:329 msgid "See :ref:`[text] ` section above." msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:232 #, fuzzy msgid "dot" msgstr "B" # type: TP #: ../../src/man/linkcheckerrc.rst:242 #, fuzzy msgid "csv" msgstr "B" #: ../../src/man/linkcheckerrc.rst:250 ../../src/man/linkcheckerrc.rst:267 msgid "**separator=**\\ *CHAR*" msgstr "" #: ../../src/man/linkcheckerrc.rst:251 msgid "Set CSV separator. Default is a comma (**,**)." msgstr "" #: ../../src/man/linkcheckerrc.rst:253 msgid "**quotechar=**\\ *CHAR*" msgstr "" #: ../../src/man/linkcheckerrc.rst:253 msgid "Set CSV quote character. Default is a double quote (**\"**)." msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:256 #, fuzzy msgid "sql" msgstr "B" #: ../../src/man/linkcheckerrc.rst:264 msgid "**dbname=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:265 msgid "Set database name to store into. Default is **linksdb**." msgstr "" #: ../../src/man/linkcheckerrc.rst:267 msgid "Set SQL command separator character. Default is a semicolon (**;**)." msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:270 #, fuzzy msgid "html" msgstr "B" #: ../../src/man/linkcheckerrc.rst:278 msgid "**colorbackground=**\\ *COLOR*" msgstr "" #: ../../src/man/linkcheckerrc.rst:279 msgid "Set HTML background color. Default is **#fff7e5**." msgstr "" #: ../../src/man/linkcheckerrc.rst:280 msgid "**colorurl=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:281 msgid "Set HTML URL color. Default is **#dcd5cf**." msgstr "" #: ../../src/man/linkcheckerrc.rst:282 msgid "**colorborder=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:283 msgid "Set HTML border color. Default is **#000000**." msgstr "" #: ../../src/man/linkcheckerrc.rst:284 msgid "**colorlink=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:285 msgid "Set HTML link color. Default is **#191c83**." msgstr "" #: ../../src/man/linkcheckerrc.rst:286 msgid "**colorwarning=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:287 msgid "Set HTML warning color. Default is **#e0954e**." msgstr "" #: ../../src/man/linkcheckerrc.rst:288 msgid "**colorerror=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:289 msgid "Set HTML error color. Default is **#db4930**." msgstr "" #: ../../src/man/linkcheckerrc.rst:291 msgid "**colorok=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:291 msgid "Set HTML valid color. Default is **#3ba557**." msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:294 #, fuzzy msgid "blacklist" msgstr "B" # type: TP #: ../../src/man/linkcheckerrc.rst:302 #, fuzzy msgid "xml" msgstr "B" # type: TP #: ../../src/man/linkcheckerrc.rst:312 #, fuzzy msgid "gxml" msgstr "B" #: ../../src/man/linkcheckerrc.rst:322 msgid "sitemap" msgstr "" #: ../../src/man/linkcheckerrc.rst:331 msgid "**priority=**\\ *FLOAT*" msgstr "" #: ../../src/man/linkcheckerrc.rst:331 msgid "" "A number between 0.0 and 1.0 determining the priority. The default priority " "for the first URL is 1.0, for all child URLs 0.5." msgstr "" #: ../../src/man/linkcheckerrc.rst:334 msgid "" "**frequency=**\\ [**always**\\ \\|\\ **hourly**\\ \\|\\ **daily**\\ \\|\\ " "**weekly**\\ \\|\\ **monthly**\\ \\|\\ **yearly**\\ \\|\\ **never**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:334 msgid "How frequently pages are changing." msgstr "" #: ../../src/man/linkcheckerrc.rst:337 msgid "LOGGER PARTS" msgstr "" #: ../../src/man/linkcheckerrc.rst:339 msgid "**all**" msgstr "" #: ../../src/man/linkcheckerrc.rst:340 msgid "for all parts" msgstr "" #: ../../src/man/linkcheckerrc.rst:341 msgid "**id**" msgstr "" #: ../../src/man/linkcheckerrc.rst:342 msgid "a unique ID for each logentry" msgstr "" #: ../../src/man/linkcheckerrc.rst:343 msgid "**realurl**" msgstr "" #: ../../src/man/linkcheckerrc.rst:344 msgid "the full url link" msgstr "" #: ../../src/man/linkcheckerrc.rst:345 msgid "**result**" msgstr "" #: ../../src/man/linkcheckerrc.rst:346 msgid "valid or invalid, with messages" msgstr "" #: ../../src/man/linkcheckerrc.rst:347 msgid "**extern**" msgstr "" #: ../../src/man/linkcheckerrc.rst:348 msgid "1 or 0, only in some logger types reported" msgstr "" #: ../../src/man/linkcheckerrc.rst:349 msgid "**base**" msgstr "" #: ../../src/man/linkcheckerrc.rst:350 msgid "base href=..." msgstr "" #: ../../src/man/linkcheckerrc.rst:351 msgid "**name**" msgstr "" #: ../../src/man/linkcheckerrc.rst:352 msgid "name and \"name\"" msgstr "" #: ../../src/man/linkcheckerrc.rst:353 msgid "**parenturl**" msgstr "" #: ../../src/man/linkcheckerrc.rst:354 msgid "if any" msgstr "" #: ../../src/man/linkcheckerrc.rst:355 msgid "**info**" msgstr "" #: ../../src/man/linkcheckerrc.rst:356 msgid "some additional info, e.g. FTP welcome messages" msgstr "" #: ../../src/man/linkcheckerrc.rst:357 msgid "**warning**" msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:358 #, fuzzy msgid "warnings" msgstr "B<-w>, B<--warnings>" #: ../../src/man/linkcheckerrc.rst:359 msgid "**dltime**" msgstr "" #: ../../src/man/linkcheckerrc.rst:360 msgid "download time" msgstr "" #: ../../src/man/linkcheckerrc.rst:361 msgid "**checktime**" msgstr "" #: ../../src/man/linkcheckerrc.rst:362 msgid "check time" msgstr "" #: ../../src/man/linkcheckerrc.rst:363 msgid "**url**" msgstr "" #: ../../src/man/linkcheckerrc.rst:364 msgid "the original url name, can be relative" msgstr "" #: ../../src/man/linkcheckerrc.rst:365 msgid "**intro**" msgstr "" #: ../../src/man/linkcheckerrc.rst:366 msgid "the blurb at the beginning, \"starting at ...\"" msgstr "" #: ../../src/man/linkcheckerrc.rst:368 msgid "**outro**" msgstr "" #: ../../src/man/linkcheckerrc.rst:368 msgid "the blurb at the end, \"found x errors ...\"" msgstr "" #: ../../src/man/linkcheckerrc.rst:371 msgid "MULTILINE" msgstr "" #: ../../src/man/linkcheckerrc.rst:373 msgid "" "Some option values can span multiple lines. Each line has to be indented for " "that to work. Lines starting with a hash (**#**) will be ignored, though " "they must still be indented." msgstr "" # type: SH #: ../../src/man/linkcheckerrc.rst:386 #, fuzzy msgid "EXAMPLE" msgstr "EXEMPLES" #: ../../src/man/linkcheckerrc.rst:402 msgid "" "All plugins have a separate section. If the section appears in the " "configuration file the plugin is enabled. Some plugins read extra options in " "their section." msgstr "" #: ../../src/man/linkcheckerrc.rst:407 msgid "AnchorCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:409 msgid "Checks validity of HTML anchors." msgstr "" #: ../../src/man/linkcheckerrc.rst:412 msgid "LocationInfo" msgstr "" #: ../../src/man/linkcheckerrc.rst:414 msgid "" "Adds the country and if possible city name of the URL host as info. Needs " "GeoIP or pygeoip and a local country or city lookup DB installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:418 msgid "RegexCheck" msgstr "" # type: Plain text #: ../../src/man/linkcheckerrc.rst:420 #, fuzzy msgid "" "Define a regular expression which prints a warning if it matches any content " "of the checked link. This applies only to valid pages, so we can get their " "content." msgstr "" "Définir une expression rationnelle. Quand cette expression rationnelle " "correspondra au contenu d'un lien vérifié, LinkChecker affichera un " "avertissement.Ceci ne s'applique qu'aux pages valides, car on peut ainsi " "récupérer leur contenu.Utilisez ceci afin de vérifier les pages qui peuvent " "contenir des messages d'erreur sous une certaine forme, comme par exemple " "\"Cette page a été déplacée\" ou \"Erreur du serveur d'application Oracle\"." "Cette option implique B<-w>." #: ../../src/man/linkcheckerrc.rst:430 msgid "**warningregex=**\\ *REGEX*" msgstr "" #: ../../src/man/linkcheckerrc.rst:425 msgid "" "Use this to check for pages that contain some form of error message, for " "example \"This page has moved\" or \"Oracle Application error\". *REGEX* " "should be unquoted." msgstr "" #: ../../src/man/linkcheckerrc.rst:429 msgid "" "Note that multiple values can be combined in the regular expression, for " "example \"(This page has moved\\|Oracle Application error)\"." msgstr "" #: ../../src/man/linkcheckerrc.rst:433 msgid "SslCertificateCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:435 msgid "" "Check SSL certificate expiration date. Only internal https: links will be " "checked. A domain will only be checked once to avoid duplicate warnings." msgstr "" #: ../../src/man/linkcheckerrc.rst:440 msgid "**sslcertwarndays=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:440 msgid "Configures the expiration warning time in days." msgstr "" #: ../../src/man/linkcheckerrc.rst:443 msgid "HtmlSyntaxCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:445 msgid "" "Check the syntax of HTML pages with the online W3C HTML validator. See " "https://validator.w3.org/docs/api.html." msgstr "" #: ../../src/man/linkcheckerrc.rst:449 msgid "HttpHeaderInfo" msgstr "" #: ../../src/man/linkcheckerrc.rst:451 msgid "Print HTTP headers in URL info." msgstr "" #: ../../src/man/linkcheckerrc.rst:455 msgid "**prefixes=**\\ *prefix1*\\ [,*prefix2*]..." msgstr "" #: ../../src/man/linkcheckerrc.rst:454 msgid "" "List of comma separated header prefixes. For example to display all HTTP " "headers that start with \"X-\"." msgstr "" #: ../../src/man/linkcheckerrc.rst:458 msgid "CssSyntaxCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:460 msgid "" "Check the syntax of HTML pages with the online W3C CSS validator. See " "https://jigsaw.w3.org/css-validator/manual.html#expert." msgstr "" #: ../../src/man/linkcheckerrc.rst:464 msgid "VirusCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:466 msgid "" "Checks the page content for virus infections with clamav. A local clamav " "daemon must be installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:470 msgid "**clamavconf=**\\ *filename*" msgstr "" #: ../../src/man/linkcheckerrc.rst:470 msgid "Filename of **clamd.conf** config file." msgstr "" #: ../../src/man/linkcheckerrc.rst:473 msgid "PdfParser" msgstr "" #: ../../src/man/linkcheckerrc.rst:475 msgid "" "Parse PDF files for URLs to check. Needs the :pypi:`pdfminer` Python package " "installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:479 msgid "WordParser" msgstr "" #: ../../src/man/linkcheckerrc.rst:481 msgid "" "Parse Word files for URLs to check. Needs the :pypi:`pywin32` Python " "extension installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:485 msgid "WARNINGS" msgstr "" #: ../../src/man/linkcheckerrc.rst:487 msgid "" "The following warnings are recognized in the 'ignorewarnings' config file " "entry:" msgstr "" #: ../../src/man/linkcheckerrc.rst:490 msgid "**file-missing-slash**" msgstr "" #: ../../src/man/linkcheckerrc.rst:491 msgid "The file: URL is missing a trailing slash." msgstr "" #: ../../src/man/linkcheckerrc.rst:492 msgid "**file-system-path**" msgstr "" #: ../../src/man/linkcheckerrc.rst:493 msgid "The file: path is not the same as the system specific path." msgstr "" #: ../../src/man/linkcheckerrc.rst:494 msgid "**ftp-missing-slash**" msgstr "" #: ../../src/man/linkcheckerrc.rst:495 msgid "The ftp: URL is missing a trailing slash." msgstr "" #: ../../src/man/linkcheckerrc.rst:496 msgid "**http-cookie-store-error**" msgstr "" #: ../../src/man/linkcheckerrc.rst:497 msgid "An error occurred while storing a cookie." msgstr "" #: ../../src/man/linkcheckerrc.rst:498 msgid "**http-empty-content**" msgstr "" #: ../../src/man/linkcheckerrc.rst:499 msgid "The URL had no content." msgstr "" #: ../../src/man/linkcheckerrc.rst:500 msgid "**mail-no-mx-host**" msgstr "" #: ../../src/man/linkcheckerrc.rst:501 msgid "The mail MX host could not be found." msgstr "" #: ../../src/man/linkcheckerrc.rst:502 msgid "**nntp-no-newsgroup**" msgstr "" #: ../../src/man/linkcheckerrc.rst:503 msgid "The NNTP newsgroup could not be found." msgstr "" #: ../../src/man/linkcheckerrc.rst:504 msgid "**nntp-no-server**" msgstr "" #: ../../src/man/linkcheckerrc.rst:505 msgid "No NNTP server was found." msgstr "" #: ../../src/man/linkcheckerrc.rst:506 msgid "**url-content-size-zero**" msgstr "" #: ../../src/man/linkcheckerrc.rst:507 msgid "The URL content size is zero." msgstr "" #: ../../src/man/linkcheckerrc.rst:508 msgid "**url-content-too-large**" msgstr "" #: ../../src/man/linkcheckerrc.rst:509 msgid "The URL content size is too large." msgstr "" #: ../../src/man/linkcheckerrc.rst:510 msgid "**url-effective-url**" msgstr "" #: ../../src/man/linkcheckerrc.rst:511 msgid "The effective URL is different from the original." msgstr "" #: ../../src/man/linkcheckerrc.rst:512 msgid "**url-error-getting-content**" msgstr "" #: ../../src/man/linkcheckerrc.rst:513 msgid "Could not get the content of the URL." msgstr "" #: ../../src/man/linkcheckerrc.rst:514 msgid "**url-obfuscated-ip**" msgstr "" #: ../../src/man/linkcheckerrc.rst:515 msgid "The IP is obfuscated." msgstr "" #: ../../src/man/linkcheckerrc.rst:517 msgid "**url-whitespace**" msgstr "" #: ../../src/man/linkcheckerrc.rst:517 msgid "The URL contains leading or trailing whitespace." msgstr "" #: ../../src/man/linkcheckerrc.rst:522 msgid ":manpage:`linkchecker(1)`" msgstr "" # type: TH #, no-wrap #~ msgid "LINKCHECKER" #~ msgstr "LINKCHECKER" # type: SH #, no-wrap #~ msgid "NAME" #~ msgstr "NOM" # type: Plain text #~ msgid "linkchecker - check HTML documents for broken links" #~ msgstr "" #~ "linkchecker - outil permettant de vérifier s'il n'y a pas de liens cassés " #~ "dans les documents HTML" # type: Plain text #, fuzzy #~ msgid "" #~ "LinkChecker features recursive checking, multithreading, output in " #~ "colored or normal text, HTML, SQL, CSV or a sitemap graph in GML or XML, " #~ "support for HTTP/1.1, HTTPS, FTP, mailto:, news:, nntp:, Telnet and local " #~ "file links, restriction of link checking with regular expression filters " #~ "for URLs, proxy support, username/password authorization for HTTP and " #~ "FTP, robots.txt exclusion protocol support, i18n support, a command line " #~ "interface and a (Fast)CGI web interface (requires HTTP server)" #~ msgstr "" #~ "LinkChecker propose une vérification récursive, du multithreading, un " #~ "affichage en couleurs ou au format texte, HTML, SQL, CSV, mais aussi un " #~ "graphique de la carte du site en GML ou XML, un support de HTTP/1.1, " #~ "HTTPS, FTP, mailto:, news:, nntp:, Telnet et les liens sur les fichiers " #~ "locaux, une vérification des liens restreinte par l'utilisation de " #~ "filtres à base d'expressions rationnelles, un support des proxys, des " #~ "autorisations nom utilisateur/mot de passe pour HTTP et FTP, un support " #~ "du protocole d'exclusion par le fichier robots.txt,un support de " #~ "l'internationalisation, une interface ligne de commandes et une interface " #~ "web CGI (rapide, qui nécessite un serveur HTTP)." # type: Plain text #, fuzzy, no-wrap #~ msgid "" #~ "The most common use checks the given domain recursively, plus any\n" #~ "URL pointing outside of the domain:\n" #~ " B\n" #~ msgstr "" #~ "L'utilisation la plus courante est de vérifier le domaine récursivement, ainsi que\n" #~ "quelques URL simples pointant en dehors du domaine :\n" #~ " B\n" # type: Plain text #, fuzzy, no-wrap #~ msgid "" #~ "Don't connect to B hosts, only check their URL syntax. All other\n" #~ "links are checked as usual:\n" #~ " B\n" #~ msgstr "" #~ "Pour ne pas se connecter aux hôtes mailto:, seulement vérifier leur syntaxe.\n" #~ "Tous les autres liens sont vérifiés comme d'habitude :\n" #~ " B\n" # type: TP #, no-wrap #~ msgid "B<-h>, B<--help>" #~ msgstr "B<-h>, B<--help>" # type: TP #, no-wrap #~ msgid "B<-I>, B<--interactive>" #~ msgstr "B<-I>, B<--interactive>" # type: Plain text #, fuzzy #~ msgid "Ask for URL if none are given on the commandline." #~ msgstr "Demander l'URL si aucune n'a été donnée sur la ligne de commande." # type: TP #, fuzzy, no-wrap #~ msgid "B<-t>I, B<--threads=>I" #~ msgstr "B<-t>I, B<--threads=>I" # type: TP #, no-wrap #~ msgid "B<--priority>" #~ msgstr "B<--priority>" # type: TP #, no-wrap #~ msgid "B<-V>, B<--version>" #~ msgstr "B<-V>, B<--version>" # type: TP #, no-wrap #~ msgid "B<-v>, B<--verbose>" #~ msgstr "B<-v>, B<--verbose>" # type: TP #, fuzzy, no-wrap #~ msgid "B<-W>I, B<--warning-regex=>I" #~ msgstr "B<-W>I, B<--warning-regex=>I" # type: TP #, fuzzy, no-wrap #~ msgid "B<--warning-size-bytes=>I" #~ msgstr "B<--warning-size-bytes=>I" # type: Plain text #, fuzzy #~ msgid "" #~ "Print a warning if content size info is available and exceeds the given " #~ "number of I." #~ msgstr "" #~ "Affiche un avertissement si la taille du contenu disponible dépasse le " #~ "nombre d'I donné.Cette option implique B<-w>." # type: TP #, no-wrap #~ msgid "B<-q>, B<--quiet>" #~ msgstr "B<-q>, B<--quiet>" # type: TP #, fuzzy, no-wrap #~ msgid "B<-o>I[BI], B<--output=>I[BI]" #~ msgstr "B<-o>I[BI], B<--output=>I[BI]" # type: TP #, fuzzy, no-wrap #~ msgid "B<-F>I[BI][BI], B<--file-output=>I[BI][BI]" #~ msgstr "B<-F>I[BI][BI], B<--file-output=>I[BI][BI]" # type: TP #, no-wrap #~ msgid "B<--no-status>" #~ msgstr "B<--no-status>" # type: TP #, fuzzy, no-wrap #~ msgid "B<-D>I, B<--debug=>I" #~ msgstr "B<-D>I, B<--debug=>I" # type: TP #, fuzzy, no-wrap #~ msgid "B<--trace>" #~ msgstr "B<--status>" # type: TP #, no-wrap #~ msgid "B<--profile>" #~ msgstr "B<--profile>" # type: Plain text #~ msgid "" #~ "Write profiling data into a file named B in the current " #~ "working directory. See also B<--viewprof>." #~ msgstr "" #~ "Écrire les données de profilage dans un fichier nommé B " #~ "dans le répertoire de travail courant. Voir aussi B<--viewprof>." # type: TP #, no-wrap #~ msgid "B<--viewprof>" #~ msgstr "B<--viewprof>" # type: Plain text #~ msgid "" #~ "Print out previously generated profiling data. See also B<--profile>." #~ msgstr "" #~ "Afficher en sortie les données de profilage générées précédemment. Voir " #~ "aussi B<--profile>." # type: TP #, fuzzy, no-wrap #~ msgid "B<-r>I, B<--recursion-level=>I" #~ msgstr "B<-r>I, B<--recursion-level=>I" # type: TP #, fuzzy, no-wrap #~ msgid "B<--no-follow-url=>I" #~ msgstr "B<--no-proxy-for=>I" # type: TP #, fuzzy, no-wrap #~ msgid "B<--ignore-url=>I" #~ msgstr "B<--no-proxy-for=>I" # type: TP #, no-wrap #~ msgid "B<-C>, B<--cookies>" #~ msgstr "B<-C>, B<--cookies>" # type: Plain text #~ msgid "" #~ "Accept and send HTTP cookies according to RFC 2109. Only cookies which " #~ "are sent back to the originating server are accepted. Sent and accepted " #~ "cookies are provided as additional logging information." #~ msgstr "" #~ "Accepter et envoyer des cookies HTTP en accord avec le RFC 2109. Seuls " #~ "les cookies qui sont renvoyés au serveur d'origine sont acceptés. Les " #~ "cookies acceptés et envoyés sont fournis comme une information " #~ "supplémentaire dans les journaux." # type: TP #, no-wrap #~ msgid "B<-a>, B<--anchors>" #~ msgstr "B<-a>, B<--anchors>" # type: Plain text #, fuzzy #~ msgid "" #~ "Check HTTP anchor references. Default is not to check anchors. This " #~ "option enables logging of the warning B." #~ msgstr "" #~ "Vérifier les références ancrées. Cette option s'applique aux URL internes " #~ "et externes. Par défaut, il n'y a pas de vérification des ancres. Cette " #~ "option implique B<-w> parce que les erreurs d'ancre sont toujours des " #~ "avertissements." # type: TP #, no-wrap #~ msgid "B<--no-anchor-caching>" #~ msgstr "B<--no-anchor-caching>" # type: Plain text #, fuzzy #~ msgid "" #~ "Treat url#anchora and url#anchorb as equal on caching. This is the " #~ "default browser behaviour, but it's not specified in the URI " #~ "specification. Use with care since broken anchors are not guaranteed to " #~ "be detected in this mode." #~ msgstr "" #~ "Traiter url#anchora et url#anchorb comme égales dans le cache. Ceci est " #~ "le comportement par défaut d'un navigateur, mais n'est pas spécifié dans " #~ "la spécification URI. À utiliser avec précaution." # type: TP #, fuzzy, no-wrap #~ msgid "B<-u>I, B<--user=>I" #~ msgstr "B<-u>I, B<--user=>I" # type: TP #, fuzzy, no-wrap #~ msgid "B<-p>I, B<--password=>I" #~ msgstr "B<-p>I, B<--password=>I" # type: TP #, fuzzy, no-wrap #~ msgid "B<-P>I, B<--pause=>I" #~ msgstr "B<-P>I, B<--pause=>I" # type: Plain text #, fuzzy #~ msgid "" #~ "Pause the given number of seconds between two subsequent connection " #~ "requests to the same host. Default is no pause between requests." #~ msgstr "" #~ "Mettre en pause I secondes entre chaque vérification d'URL. Cette " #~ "option implique B<-t0>. Par défaut, il n'y a pas de pause entre les " #~ "requêtes." # type: TP #, fuzzy, no-wrap #~ msgid "B<-N>I, B<--nntp-server=>I" #~ msgstr "B<-N>I, B<--nntp-server=>I" # type: TP #, fuzzy, no-wrap #~ msgid "B<--no-proxy-for=>I" #~ msgstr "B<--no-proxy-for=>I" # type: TP #, no-wrap #~ msgid "B" #~ msgstr "B" # type: Plain text #, fuzzy #~ msgid "" #~ "To use a proxy set $http_proxy, $https_proxy, $ftp_proxy on Unix or " #~ "Windows to the proxy URL. The URL should be of the form B[IB<:>IB<@>]I[B<:>I], for example B, or B. On a Mac use the " #~ "Internet Config to select a proxy." #~ msgstr "" #~ "Pour utiliser les proxys, positionnez $http_proxy, $https_proxy sur Unix " #~ "ou Windows.Sur un Mac, utilisez la configuration Internet." # type: Plain text #, fuzzy #~ msgid "" #~ "URLs on the commandline starting with B are treated like B, URLs starting with B are treated like B. You " #~ "can also give local files as arguments." #~ msgstr "" #~ "Les URL sur la ligne de commande commençant par B sont traitées " #~ "comme B, les URL commençant par B sont traitées comme " #~ "B. Vous pouvez aussi mettre des noms de fichiers locaux " #~ "comme arguments." # type: Plain text #~ msgid "B, B, B - specify output language" #~ msgstr "B, B, B - spécifie la langue en sortie" # type: IP #, no-wrap #~ msgid "\\(bu" #~ msgstr "\\(bu" # type: SH #, no-wrap #~ msgid "AUTHOR" #~ msgstr "AUTEUR" # type: Plain text #~ msgid "Bastian Kleineidam Ecalvin@users.sourceforge.netE" #~ msgstr "" #~ "Bastian Kleineidam Ecalvin@users.sourceforge.netE\n" #~ "\n" #~ "Ce document est une traduction, réalisée par Yann Verley Eyann." #~ "verley@free.fr le 29 novembre 2004. L'équipe de traduction a fait le " #~ "maximum pour réaliser une adaptation française de qualité. La version " #~ "anglaise la plus à jour de ce document est toujours consultable via la " #~ "commande :\n" #~ " LANGUAGE=en man linkchecker\n" #~ "\n" #~ "N'hésitez pas à signaler à l'auteur ou au traducteur, selon le cas, toute " #~ "erreur dans cette page de manuel." linkchecker-10.5.0/doc/install.txt000066400000000000000000000152461466565367000170650ustar00rootroot00000000000000Installation ============ If you are upgrading from older versions of LinkChecker you should also read the upgrading documentation stored in upgrading.txt. Installing a LinkChecker release uses pre-built distribution packages. Building the distribution packages requires hatchling_ and hatch-vcs_, and for application translations to be compiled polib_ needs to be installed. After the sdist/wheel has been built polib_ can be removed. pip-run_ may be useful for this. There are several steps to resolve problems with detecting the character encoding of checked HTML pages: first ensure the web server, if used, is not returning an incorrect charset in the Content-Type header; second, if possible add a meta element to the HTML page with the correct charset; finally, check chardet_ is not installed, Requests >= 2.26 will install charset-normalizer_, Beautiful Soup has its own encoding detector but will use in order of preference cchardet_, chardet_ or charset-normalizer_ (Beautiful Soup >= 4.11). You might find that one of the other three detectors works better for your pages. There may already be a system copy of e.g. chardet installed; installing LinkChecker in a Python venv_ gives control over which packages are used. .. _chardet: https://pypi.org/project/chardet/ .. _charset-normalizer: https://pypi.org/project/charset-normalizer/ .. _pip-run: https://pypi.org/project/pip-run/ .. _cchardet: https://pypi.org/project/cchardet/ .. _polib: https://pypi.org/project/polib/ .. _hatchling: https://pypi.org/project/hatchling/ .. _hatch-vcs: https://pypi.org/project/hatch-vcs/ .. _venv: https://docs.python.org/3/library/venv.html#creating-virtual-environments Setup with pip(x) ------------------ pip_ or pipx_ can be used to install LinkChecker on the local system. To install the latest release from PyPI: ``pip3 install linkchecker`` or: ``pipx install linkchecker`` There is no need to wait for releases, every update to LinkChecker gets a unique version number and is subjected to the test suite. You can easily install the latest source from the LinkChecker GitHub repository. First, if you want application translations: ``pip3 install polib`` Then: ``pip3 install https://github.com/linkchecker/linkchecker/archive/master.tar.gz`` .. _pip: https://pypi.org/project/pip/ .. _pipx: https://pypi.org/project/pipx/ Setup for Windows ----------------- Python from the Microsoft Store does include pip_, but installing within Windows Subsystem for Linux (WSL) is the preferred option: https://docs.microsoft.com/en-us/windows/python/beginners Setup for macOS ------------------ Python from Homebrew includes pip_. Otherwise ``python3 -m ensurepip --upgrade`` can be used to install pip_ (untested): https://pip.pypa.io/en/stable/installation/ Setup for GNU/Linux ------------------- On major Linux distributions (Debian, Gentoo, Fedora, Ubuntu), the ``linkchecker`` package is available for installation. To install the latest LinkChecker pip_ will be available, often as a package e.g. ``python3-pip``, a pipx_ package may also be found e.g. ``pipx``. You may wish to install your distribution's copies of LinkChecker's dependencies before using pip to install LinkChecker. e.g. for Debian/Ubuntu: ``apt install python3-bs4 python3-dnspython python3-requests`` If those packages are too old pip will install newer versions. To use the dependencies from your distribution if installing LinkChecker with pipx: ``pipx install --system-site-packages linkchecker`` Manual setup for Unix systems ----------------------------- First, install the required software. 1. Python hatchling package from https://pypi.org/project/hatchling/ 2. Python hatch-vcs package from https://pypi.org/project/hatch-vcs/ 3. Python Requests package from https://pypi.org/project/requests/ 4. Python Beautiful Soup package from https://pypi.org/project/beautifulsoup4/ 5. Python dnspython package from https://pypi.org/project/dnspython/ 6. *Optional, build time only, for translations:* Python polib package from https://pypi.org/project/polib/ 7. *Optional, for bash-completion:* Python argcomplete package from https://pypi.org/project/argcomplete/ 8. *Optional, for displaying country codes:* Python GeoIP package from https://pypi.org/project/GeoIP/ 9. *Optional, for reading PDF files:* Python pdfminer.six package from https://pypi.org/project/pdfminer.six/ 10. *Optional, used for Virus checking:* ClamAv from https://www.clamav.net/ 11. *Optional, to run the WSGI web interface:* Apache from https://httpd.apache.org/ mod_wsgi from https://pypi.org/project/mod-wsgi/ Note for developers: if you want to regenerate the po/linkchecker.pot template from the source files, you will need xgettext with Python support. This is available in gettext >= 0.12. Clone the LinkChecker repository: ``git clone https://github.com/linkchecker/linkchecker.git`` ``cd linkchecker`` Build the distribution wheel: ``hatchling build`` Now install the application from the wheel: ``pip install --no-index --user dist/LinkChecker--py3-none-any.whl`` Note that you may have to adjust your PATH and PYTHONPATH environment variables, eg. by adding the commands ``export PYTHONPATH=$HOME/lib/python`` and ``export PATH=$PATH:$HOME/bin`` to your shell configuration file. For more information look at the `Modifying Python's search path`_ documentation. .. _Modifying Python's search path: https://docs.python.org/3/install/#inst-search-path After installation ------------------ LinkChecker is now installed. Have fun! WSGI web interface ----------------------- The included WSGI script can run LinkChecker with a nice graphical web interface. You can use and adjust the example HTML files in the lconline directory to run the script. 1. Note that running LinkChecker requires CPU and memory resources. Allowing a WSGI script to execute such a program for possibly a large number of users might deplete those resources. Be sure to only allow access from trusted sites to this script. 2. Copy the script lc.wsgi in the WSGI directory. 3. Adjust the "action=..." parameter in lconline/lc_cgi.html to point to your WSGI script. 4. If you use Apache, copy config/linkchecker.apache2.conf into your Apache configuration directory (eg. /etc/apache2/conf.d) and enable it. 5. Load the lconline/index.html file, enter an URL and click on the check button. 6. If something goes wrong, check the following: a) look in the error log of your web server b) be sure that you have enabled WSGI support in your web server, for example by installing mod_wsgi for Apache c) be sure that you have enabled the negotiation and versioning modules for Apache: a2enmod version a2enmod negotiation linkchecker-10.5.0/doc/man/000077500000000000000000000000001466565367000154215ustar00rootroot00000000000000linkchecker-10.5.0/doc/man/de/000077500000000000000000000000001466565367000160115ustar00rootroot00000000000000linkchecker-10.5.0/doc/man/de/linkchecker.1000066400000000000000000000477161466565367000203740ustar00rootroot00000000000000.\" Man page generated from reStructuredText. . . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .TH "LINKCHECKER" "1" "August 27, 2024" "10.4.0.post49+g7cf5037e" "LinkChecker" .SH NAME linkchecker \- Kommandozeilenprogramm zum Prüfen von HTML Dokumenten und Webseiten auf ungültige Verknüpfungen .SH SYNTAX .sp \fBlinkchecker\fP [\fIOptionen\fP] [\fIDatei\-oder\-URL\fP]... .SH BESCHREIBUNG .sp LinkChecker beinhaltet .INDENT 0.0 .IP \(bu 2 rekursives Prüfen und Multithreading .IP \(bu 2 Ausgabe als farbigen oder normalen Text, HTML, SQL, CSV, XML oder einen Sitemap\-Graphen in verschiedenen Formaten .IP \(bu 2 support for HTTP/1.1, HTTPS, FTP, mailto: and local file links .IP \(bu 2 Einschränkung der Linküberprüfung mit URL\-Filter .IP \(bu 2 Proxy\-Unterstützung .IP \(bu 2 username/password authorization for HTTP and FTP .IP \(bu 2 Unterstützung des robots.txt Protokolls .IP \(bu 2 Unterstützung für Cookies .IP \(bu 2 Unterstützung für HTML5 .IP \(bu 2 Antivirusprüfung .IP \(bu 2 ein Kommandozeilenprogramm und web interface .UNINDENT .SH BEISPIELE .sp Der häufigste Gebrauchsfall prüft die angegebene Domäne rekursiv: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ linkchecker http://www.example.com/ .ft P .fi .UNINDENT .UNINDENT .sp Beachten Sie dass dies die komplette Domäne überprüft, welche aus mehreren tausend URLs bestehen kann. Benutzen Sie die Option \fI\%\-r\fP, um die Rekursionstiefe zu beschränken. .sp Prüfe keine \fB/secret\fP URLs. Alle anderen Verknüpfungen werden wie üblich geprüft: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ linkchecker \-\-ignore\-url=/secret mysite.example.com .ft P .fi .UNINDENT .UNINDENT .sp Überprüfung einer lokalen HTML Datei unter Unix: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ linkchecker ../bla.html .ft P .fi .UNINDENT .UNINDENT .sp Überprüfung einer lokalen HTML Datei unter Windows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C C:\e> linkchecker c:empest.html .ft P .fi .UNINDENT .UNINDENT .sp Sie können den \fBhttp://\fP URL Anteil weglassen wenn die Domäne mit \fBwww.\fP beginnt: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ linkchecker www.example.com .ft P .fi .UNINDENT .UNINDENT .sp Sie können den \fBftp://\fP URL Anteil weglassen wenn die Domäne mit \fBftp.\fP beginnt: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ linkchecker \-r0 ftp.example.com .ft P .fi .UNINDENT .UNINDENT .sp Erzeuge einen Sitemap Graphen und konvertiere ihn mit dem graphviz dot Programm: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ linkchecker \-odot \-v www.example.com | dot \-Tps > sitemap.ps .ft P .fi .UNINDENT .UNINDENT .SH OPTIONEN .SS Allgemeine Optionen .INDENT 0.0 .TP .B \-f FILENAME, \-\-config=FILENAME Use FILENAME as configuration file. By default LinkChecker uses $XDG_CONFIG_HOME/linkchecker/linkcheckerrc. .UNINDENT .INDENT 0.0 .TP .B \-h, \-\-help Hilfe! Gebe Gebrauchsanweisung für dieses Programm aus. .UNINDENT .INDENT 0.0 .TP .B \-t NUMBER, \-\-threads=NUMBER Generiere nicht mehr als die angegebene Anzahl von Threads. Die Standardanzahl von Threads ist 10. Um Threads zu deaktivieren, geben Sie eine nicht positive Nummer an. .UNINDENT .INDENT 0.0 .TP .B \-V, \-\-version Gebe die Version aus und beende das Programm. .UNINDENT .INDENT 0.0 .TP .B \-\-list\-plugins Print available check plugins and exit. .UNINDENT .SS Ausgabeoptionen .SS URL checking results .INDENT 0.0 .TP .B \-F TYPE[/ENCODING][/FILENAME], \-\-file\-output=TYPE[/ENCODING][/FILENAME] Output to a file linkchecker\-out.TYPE, $XDG_DATA_HOME/linkchecker/failures for the failures output type, or FILENAME if specified. The ENCODING specifies the output encoding, the default is that of your locale. Valid encodings are listed at \X'tty: link https://docs.python.org/library/codecs.html#standard-encodings'\fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\X'tty: link'\&. The FILENAME and ENCODING parts of the none output type will be ignored, else if the file already exists, it will be overwritten. You can specify this option more than once. Valid file output TYPEs are text, html, sql, csv, gml, dot, xml, sitemap, none or failures. Default is no file output. The various output types are documented below. Note that you can suppress all console output with the option \fI\%\-o\fP \fInone\fP\&. .UNINDENT .INDENT 0.0 .TP .B \-\-no\-warnings Gebe keine Warnungen aus. Standard ist die Ausgabe von Warnungen. .UNINDENT .INDENT 0.0 .TP .B \-o TYPE[/ENCODING], \-\-output=TYPE[/ENCODING] Specify the console output type as text, html, sql, csv, gml, dot, xml, sitemap, none or failures. Default type is text. The various output types are documented below. The ENCODING specifies the output encoding, the default is that of your locale. Valid encodings are listed at \X'tty: link https://docs.python.org/library/codecs.html#standard-encodings'\fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\X'tty: link'\&. .UNINDENT .INDENT 0.0 .TP .B \-v, \-\-verbose Log all checked URLs, overriding \fI\%\-\-no\-warnings\fP\&. Default is to log only errors and warnings. .UNINDENT .SS Progress updates .INDENT 0.0 .TP .B \-\-no\-status Do not print URL check status messages. .UNINDENT .SS Application .INDENT 0.0 .TP .B \-D STRING, \-\-debug=STRING Print debugging output for the given logger. Available debug loggers are cmdline, checking, cache, plugin and all. all is an alias for all available loggers. This option can be given multiple times to debug with more than one logger. .UNINDENT .SS Quiet .INDENT 0.0 .TP .B \-q, \-\-quiet Quiet operation, an alias for \fI\%\-o\fP \fInone\fP that also hides application information messages. This is only useful with \fI\%\-F\fP, else no results will be output. .UNINDENT .SS Optionen zum Prüfen .INDENT 0.0 .TP .B \-\-cookiefile=FILENAME Use initial cookie data read from a file. The cookie data format is explained below. .UNINDENT .INDENT 0.0 .TP .B \-\-check\-extern Check external URLs. .UNINDENT .INDENT 0.0 .TP .B \-\-ignore\-url=REGEX URLs matching the given regular expression will only be syntax checked. This option can be given multiple times. See section \fI\%REGULAR EXPRESSIONS\fP for more info. .UNINDENT .INDENT 0.0 .TP .B \-\-no\-follow\-url=REGEX Prüfe URLs die auf den regulären Ausdruck zutreffen, aber führe keine Rekursion durch. Diese Option kann mehrmals angegeben werden. Siehe Abschnitt \fI\%REGULAR EXPRESSIONS\fP für weitere Infos. .UNINDENT .INDENT 0.0 .TP .B \-\-no\-robots Check URLs regardless of any robots.txt files. .UNINDENT .INDENT 0.0 .TP .B \-p, \-\-password Liest ein Passwort von der Kommandozeile und verwende es für HTTP und FTP Autorisierung. Für FTP ist das Standardpasswort anonymous@. Für HTTP gibt es kein Standardpasswort. Siehe auch \fI\%\-u\fP\&. .UNINDENT .INDENT 0.0 .TP .B \-r NUMBER, \-\-recursion\-level=NUMBER Prüfe rekursiv alle URLs bis zu der angegebenen Tiefe. Eine negative Tiefe bewirkt unendliche Rekursion. Standard Tiefe ist unendlich. .UNINDENT .INDENT 0.0 .TP .B \-\-timeout=NUMBER Setze den Timeout für TCP\-Verbindungen in Sekunden. Der Standard Timeout ist 60 Sekunden. .UNINDENT .INDENT 0.0 .TP .B \-u STRING, \-\-user=STRING Verwende den angegebenen Benutzernamen für HTTP und FTP Autorisierung. Für FTP ist der Standardname anonymous. Für HTTP gibt es keinen Standardnamen. Siehe auch \fI\%\-p\fP\&. .UNINDENT .INDENT 0.0 .TP .B \-\-user\-agent=STRING Gibt den User\-Agent an, der zu HTTP\-Servern geschickt wird, z.B. \(dqMozilla/4.0\(dq. Der Standard ist \(dqLinkChecker/X.Y\(dq, wobei X.Y die aktuelle Version von LinkChecker ist. .UNINDENT .SS Input options .INDENT 0.0 .TP .B \-\-stdin Read from stdin a list of white\-space separated URLs to check. .UNINDENT .INDENT 0.0 .TP .B FILE\-OR\-URL The location to start checking with. A file can be a simple list of URLs, one per line, if the first line is \(dq# LinkChecker URL list\(dq. .UNINDENT .SH KONFIGURATIONSDATEIEN .sp Konfigurationsdateien können alle obigen Optionen enthalten. Sie können zudem Optionen enthalten, welche nicht auf der Kommandozeile gesetzt werden können. Siehe \fB\fI\%linkcheckerrc(5)\fP\fP für mehr Informationen. .SH AUSGABETYPEN .sp Beachten Sie, dass standardmäßig nur Fehler und Warnungen protokolliert werden. Sie sollten die \fI\%\-\-verbose\fP Option benutzen, um eine komplette URL Liste zu erhalten, besonders bei Ausgabe eines Sitemap\-Graphen. .INDENT 0.0 .TP \fBtext\fP Standard Textausgabe in \(dqSchlüssel: Wert\(dq\-Form. .TP \fBhtml\fP Gebe URLs in \(dqSchlüssel: Wert\(dq\-Form als HTML formatiert aus. Besitzt zudem Verknüpfungen auf die referenzierten Seiten. Ungültige URLs haben Verknüpfungen zur HTML und CSS Syntaxprüfung angehängt. .TP \fBcsv\fP Gebe Prüfresultat in CSV\-Format aus mit einer URL pro Zeile. .TP \fBgml\fP Gebe Vater\-Kind Beziehungen zwischen verknüpften URLs als GML Graphen aus. .TP \fBdot\fP Gebe Vater\-Kind Beziehungen zwischen verknüpften URLs als DOT Graphen aus. .TP \fBgxml\fP Gebe Prüfresultat als GraphXML\-Datei aus. .TP \fBxml\fP Gebe Prüfresultat als maschinenlesbare XML\-Datei aus. .TP \fBsitemap\fP Protokolliere Prüfergebnisse als XML Sitemap dessen Format unter \X'tty: link https://www.sitemaps.org/protocol.html'\fI\%https://www.sitemaps.org/protocol.html\fP\X'tty: link' dokumentiert ist. .TP \fBsql\fP Gebe Prüfresultat als SQL Skript mit INSERT Befehlen aus. Ein Beispielskript, um die initiale SQL Tabelle zu erstellen ist unter create.sql zu finden. .TP \fBfailures\fP Suitable for cron jobs. Logs the check result into a file \fB$XDG_DATA_HOME/linkchecker/failures\fP which only contains entries with invalid URLs and the number of times they have failed. .TP \fBnone\fP Gibt nichts aus. Für Debugging oder Prüfen des Rückgabewerts geeignet. .UNINDENT .SH REGULÄRE AUSDRÜCKE .sp LinkChecker akzeptiert Pythons reguläre Ausdrücke. Siehe \X'tty: link https://docs.python.org/howto/regex.html'\fI\%https://docs.python.org/howto/regex.html\fP\X'tty: link' für eine Einführung. Eine Ergänzung ist, dass ein regulärer Ausdruck negiert wird falls er mit einem Ausrufezeichen beginnt. .SH COOKIE-DATEIEN .sp Eine Cookie\-Datei enthält Standard HTTP\-Header (RFC 2616) mit den folgenden möglichen Namen: .INDENT 0.0 .TP \fBHost\fP (erforderlich) Setzt die Domäne für die die Cookies gültig sind. .TP \fBPath\fP (optional) Gibt den Pfad für den die Cookies gültig sind; Standardpfad ist \fB/\fP\&. .TP \fBSet\-cookie\fP (erforderlich) Setzt den Cookie Name/Wert. Kann mehrmals angegeben werden. .UNINDENT .sp Mehrere Einträge sind durch eine Leerzeile zu trennen. Das untige Beispiel sendet zwei Cookies zu allen URLs die mit \fBhttp://example.org/hello/\fP beginnen, und eins zu allen URLs die mit \fBhttps://example.org\fP beginnen: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Host: example.com Path: /hello Set\-cookie: ID=\(dqsmee\(dq Set\-cookie: spam=\(dqegg\(dq .ft P .fi .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Host: example.org Set\-cookie: baggage=\(dqelitist\(dq; comment=\(dqhologram\(dq .ft P .fi .UNINDENT .UNINDENT .SH PROXY UNTERSTÜTZUNG .sp To use a proxy on Unix or Windows set the \fI\%http_proxy\fP or \fI\%https_proxy\fP environment variables to the proxy URL. The URL should be of the form \fBhttp://\fP[\fIuser\fP\fB:\fP\fIpass\fP\fB@\fP]\fIhost\fP[\fB:\fP\fIport\fP]. LinkChecker also detects manual proxy settings of Internet Explorer under Windows systems. On a Mac use the Internet Config to select a proxy. You can also set a comma\-separated domain list in the \fI\%no_proxy\fP environment variable to ignore any proxy settings for these domains. The \fI\%curl_ca_bundle\fP environment variable can be used to identify an alternative certificate bundle to be used with an HTTPS proxy. .sp Einen HTTP\-Proxy unter Unix anzugeben sieht beispielsweise so aus: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ export http_proxy=\(dqhttp://proxy.example.com:8080\(dq .ft P .fi .UNINDENT .UNINDENT .sp Proxy\-Authentifizierung wird ebenfalls unterstützt: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ export http_proxy=\(dqhttp://user1:mypass@proxy.example.org:8081\(dq .ft P .fi .UNINDENT .UNINDENT .sp Setzen eines Proxies unter der Windows Befehlszeile: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C C:\e> set http_proxy=http://proxy.example.com:8080 .ft P .fi .UNINDENT .UNINDENT .SH DURCHGEFÜHRTE PRÜFUNGEN .sp Alle URLs müssen einen ersten Syntaxtest bestehen. Kleine Kodierungsfehler ergeben eine Warnung, jede andere ungültige Syntaxfehler sind Fehler. Nach dem Bestehen des Syntaxtests wird die URL in die Schlange zum Verbindungstest gestellt. Alle Verbindungstests sind weiter unten beschrieben. .INDENT 0.0 .TP HTTP Verknüpfungen (\fBhttp:\fP, \fBhttps:\fP) Nach Verbinden zu dem gegebenen HTTP\-Server wird der eingegebene Pfad oder Query angefordert. Alle Umleitungen werden verfolgt, und falls ein Benutzer/Passwort angegeben wurde werden diese falls notwendig als Authorisierung benutzt. Alle finalen HTTP Statuscodes, die nicht dem Muster 2xx entsprechen, werden als Fehler ausgegeben. .sp Der Inhalt von HTML\-Seiten wird rekursiv geprüft. .TP Lokale Dateien (\fBfile:\fP) Eine reguläre, lesbare Datei die geöffnet werden kann ist gültig. Ein lesbares Verzeichnis ist ebenfalls gültig. Alle anderen Dateien, zum Beispiel Gerätedateien, unlesbare oder nicht existente Dateien ergeben einen Fehler. .sp HTML\- oder andere untersuchbare Dateiinhalte werden rekursiv geprüft. .TP Mail\-Links (\fBmailto:\fP) Ein \X'tty: link mailto:-Link'\fI\%mailto:\-Link\fP\X'tty: link' ergibt eine Liste von E\-Mail\-Adressen. Falls eine Adresse fehlerhaft ist, wird die ganze Liste als fehlerhaft angesehen. Für jede E\-Mail\-Adresse werden die folgenden Dinge geprüft: .INDENT 7.0 .IP 1. 3 Check the address syntax, both the parts before and after the @ sign. .IP 2. 3 Look up the MX DNS records. If we found no MX record, print an error. .IP 3. 3 Check if one of the mail hosts accept an SMTP connection. Check hosts with higher priority first. If no host accepts SMTP, we print a warning. .IP 4. 3 Try to verify the address with the VRFY command. If we got an answer, print the verified address as an info. .UNINDENT .TP FTP\-Links (\fBftp:\fP) Für FTP\-Links wird Folgendes geprüft: .INDENT 7.0 .IP 1. 3 Eine Verbindung zum angegeben Rechner wird aufgebaut .IP 2. 3 Versuche, sich mit dem gegebenen Nutzer und Passwort anzumelden. Der Standardbenutzer ist \fBanonymous\fP, das Standardpasswort ist \fBanonymous@\fP\&. .IP 3. 3 Versuche, in das angegebene Verzeichnis zu wechseln .IP 4. 3 Liste die Dateien im Verzeichnis auf mit dem NLST\-Befehl .UNINDENT .TP Nicht unterstützte Links (\fBjavascript:\fP, etc.) Ein nicht unterstützter Link wird nur eine Warnung ausgeben. Weitere Prüfungen werden nicht durchgeführt. .sp Die komplette Liste von erkannten, aber nicht unterstützten Links ist in der Quelldatei \X'tty: link https://github.com/linkchecker/linkchecker/blob/master/linkcheck/checker/unknownurl.py'\fI\%linkcheck/checker/unknownurl.py\fP\X'tty: link'\&. Die bekanntesten davon dürften JavaScript\-Links sein. .UNINDENT .SH SITEMAPS .sp Sitemaps are parsed for links to check and can be detected either from a sitemap entry in a robots.txt, or when passed as a \fI\%FILE\-OR\-URL\fP argument in which case detection requires the urlset/sitemapindex tag to be within the first 70 characters of the sitemap. Compressed sitemap files are not supported. .SH PLUGINS .sp There are two plugin types: connection and content plugins. Connection plugins are run after a successful connection to the URL host. Content plugins are run if the URL type has content (mailto: URLs have no content for example) and if the check is not forbidden (ie. by HTTP robots.txt). Use the option \fI\%\-\-list\-plugins\fP for a list of plugins and their documentation. All plugins are enabled via the \fB\fI\%linkcheckerrc(5)\fP\fP configuration file. .SH REKURSION .sp Bevor eine URL rekursiv geprüft wird, hat diese mehrere Bedingungen zu erfüllen. Diese werden in folgender Reihenfolge geprüft: .INDENT 0.0 .IP 1. 3 Eine URL muss gültig sein. .IP 2. 3 Der URL\-Inhalt muss analysierbar sein. Dies beinhaltet zur Zeit HTML\-Dateien, Opera Lesezeichen, und Verzeichnisse. Falls ein Dateityp nicht erkannt wird, (zum Beispiel weil er keine bekannte HTML\-Dateierweiterung besitzt, und der Inhalt nicht nach HTML aussieht), wird der Inhalt als nicht analysierbar angesehen. .IP 3. 3 Der URL\-Inhalt muss ladbar sein. Dies ist normalerweise der Fall, mit Ausnahme von mailto: oder unbekannten URL\-Typen. .IP 4. 3 Die maximale Rekursionstiefe darf nicht überschritten werden. Diese wird mit der Option \fI\%\-\-recursion\-level\fP konfiguriert und ist standardmäßig nicht limitiert. .IP 5. 3 Die URL darf nicht in der Liste von ignorierten URLs sein. Die ignorierten URLs werden mit der Option \fI\%\-\-ignore\-url\fP konfiguriert. .IP 6. 3 Das Robots Exclusion Protocol muss es erlauben, dass Verknüpfungen in der URL rekursiv verfolgt werden können. Dies wird geprüft, indem in den HTML Kopfdaten nach der \(dqnofollow\(dq\-Direktive gesucht wird. .UNINDENT .sp Beachten Sie, dass die Verzeichnisrekursion alle Dateien in diesem Verzeichnis liest, nicht nur eine Untermenge wie bspw. \fBindex.htm\fP\&. .SH BEMERKUNGEN .sp URLs von der Kommandozeile die mit \fBftp.\fP beginnen werden wie \fBftp://ftp.\fP behandelt, URLs die mit \fBwww.\fP beginnen wie \fBhttp://www.\fP\&. Sie können auch lokale Dateien angeben. Falls sich Ihr System automatisch mit dem Internet verbindet (z.B. mit diald), wird es dies tun wenn Sie Links prüfen, die nicht auf Ihren lokalen Rechner verweisen Benutzen Sie die Option \fI\%\-\-ignore\-url\fP, um dies zu verhindern. .sp Javascript Links werden nicht unterstützt. .sp Wenn Ihr System keine Threads unterstützt, deaktiviert diese LinkChecker automatisch. .sp Sie können mehrere Benutzer/Passwort Paare in einer Konfigurationsdatei angeben. .SH UMGEBUNG .INDENT 0.0 .TP .B http_proxy gibt Standard HTTP Proxy an .UNINDENT .INDENT 0.0 .TP .B https_proxy specifies default HTTPS proxy server .UNINDENT .INDENT 0.0 .TP .B curl_ca_bundle an alternative certificate bundle to be used with an HTTPS proxy .UNINDENT .INDENT 0.0 .TP .B no_proxy kommaseparierte Liste von Domains, die nicht über einen Proxy\-Server kontaktiert werden .UNINDENT .INDENT 0.0 .TP .B LC_MESSAGES, LANG, LANGUAGE gibt Ausgabesprache an .UNINDENT .SH RÜCKGABEWERT .sp Der Rückgabewert ist 2 falls .INDENT 0.0 .IP \(bu 2 ein Programmfehler aufgetreten ist. .UNINDENT .sp Der Rückgabewert ist 1 falls .INDENT 0.0 .IP \(bu 2 ungültige Verknüpfungen gefunden wurden oder .IP \(bu 2 Warnungen gefunden wurden und Warnungen aktiviert sind .UNINDENT .sp Sonst ist der Rückgabewert Null. .SH LIMITIERUNGEN .sp LinkChecker benutzt Hauptspeicher für jede zu prüfende URL, die in der Warteschlange steht. Mit tausenden solcher URLs kann die Menge des benutzten Hauptspeichers sehr groß werden. Dies könnte das Programm oder sogar das gesamte System verlangsamen. .SH DATEIEN .sp \fB$XDG_CONFIG_HOME/linkchecker/linkcheckerrc\fP \- default configuration file .sp \fB$XDG_DATA_HOME/linkchecker/failures\fP \- default failures logger output filename .sp \fBlinkchecker\-out.\fP\fITYP\fP \- Standard Dateiname der Logausgabe .SH SIEHE AUCH .sp \fB\fI\%linkcheckerrc(5)\fP\fP .sp \X'tty: link https://docs.python.org/library/codecs.html#standard-encodings'\fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\X'tty: link' \- gültige Ausgabe Enkodierungen .sp \X'tty: link https://docs.python.org/howto/regex.html'\fI\%https://docs.python.org/howto/regex.html\fP\X'tty: link' \- Dokumentation zu regulären Ausdrücken .SH AUTHOR Bastian Kleineidam .SH COPYRIGHT 2000-2016 Bastian Kleineidam, 2010-2024 LinkChecker Authors .\" Generated by docutils manpage writer. . linkchecker-10.5.0/doc/man/de/linkcheckerrc.5000066400000000000000000000563521466565367000207210ustar00rootroot00000000000000.\" Man page generated from reStructuredText. . . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .TH "LINKCHECKERRC" "5" "August 27, 2024" "10.4.0.post49+g7cf5037e" "LinkChecker" .SH NAME linkcheckerrc \- Konfigurationsdatei für LinkChecker .SH BESCHREIBUNG .sp \fBlinkcheckerrc\fP is the configuration file for LinkChecker. The file is written in an INI\-style format. The default file location is \fB$XDG_CONFIG_HOME/linkchecker/linkcheckerrc\fP or else \fB~/.config/linkchecker/linkcheckerrc\fP on Unix, \fB%HOMEPATH%\e.config\elinkchecker\elinkcheckerrc\fP on Windows systems. .SH EIGENSCHAFTEN .SS checking .INDENT 0.0 .TP \fBcookiefile=\fP\fIDateiname\fP Lese eine Datei mit Cookie\-Daten. Das Cookie Datenformat wird in \fB\fI\%linkchecker(1)\fP\fP erklärt. Kommandozeilenoption: \fI\%\-\-cookiefile\fP .TP \fBdebugmemory=\fP[\fB0\fP|\fB1\fP] Write memory allocation statistics to a file on exit, requires \X'tty: link https://pypi.org/project/meliae/'\fI\%meliae\fP\X'tty: link'\&. The default is not to write the file. Command line option: none .TP \fBlocalwebroot=\fP\fISTRING\fP Beachten Sie dass das angegebene Verzeichnis in URL\-Syntax sein muss, d.h. es muss einen normalen statt einen umgekehrten Schrägstrich zum Aneinanderfügen von Verzeichnissen benutzen. Und das angegebene Verzeichnis muss mit einem Schrägstrich enden. Kommandozeilenoption: none .TP \fBrecursionlevel=\fP\fINUMMER\fP Prüfe rekursiv alle URLs bis zu der angegebenen Tiefe. Eine negative Tiefe bewirkt unendliche Rekursion. Standard Tiefe ist unendlich. Kommandozeilenoption: \fI\%\-\-recursion\-level\fP .TP \fBthreads=\fP\fINUMMER\fP Generiere nicht mehr als die angegebene Anzahl von Threads. Die Standardanzahl von Threads ist 10. Um Threads zu deaktivieren, geben Sie eine nicht positive Nummer an. Kommandozeilenoption: \fI\%\-\-threads\fP .TP \fBtimeout=\fP\fINUMMER\fP Setze den Timeout für TCP\-Verbindungen in Sekunden. Der Standard Timeout ist 60 Sekunden. Kommandozeilenoption: \fI\%\-\-timeout\fP .TP \fBaborttimeout=\fP\fINUMMER\fP Time to wait for checks to finish after the user aborts the first time (with Ctrl\-C or the abort button). The default abort timeout is 300 seconds. Command line option: none .TP \fBuseragent=\fP\fISTRING\fP Gibt den User\-Agent an, der zu HTTP\-Servern geschickt wird, z.B. \(dqMozilla/4.0\(dq. Der Standard ist \(dqLinkChecker/X.Y\(dq, wobei X.Y die aktuelle Version von LinkChecker ist. Kommandozeilenoption: \fI\%\-\-user\-agent\fP .TP \fBsslverify=\fP[\fB0\fP|\fB1\fP|\fIfilename\fP] Falls der Wert Null ist werden SSL Zertifikate nicht überprüft. Falls er auf Eins gesetzt wird (der Standard) werden SSL Zertifikate mit der gelieferten CA Zertifikatsdatei geprüft. Falls ein Dateiname angegeben ist wird dieser zur Prüfung verwendet. Kommandozeilenoption: none .TP \fBmaxrunseconds=\fP\fINUMMER\fP Hört nach der angegebenen Anzahl von Sekunden auf, neue URLs zu prüfen. Dies ist dasselbe als wenn der Benutzer nach der gegebenen Anzahl von Sekunden stoppt (durch Drücken von Strg\-C). Kommandozeilenoption: none .TP \fBmaxfilesizedownload=\fP\fINUMBER\fP Files larger than NUMBER bytes will be ignored, without downloading anything if accessed over http and an accurate Content\-Length header was returned. No more than this amount of a file will be downloaded. The default is 5242880 (5 MB). Command line option: none .TP \fBmaxfilesizeparse=\fP\fINUMBER\fP Files larger than NUMBER bytes will not be parsed for links. The default is 1048576 (1 MB). Command line option: none .TP \fBmaxnumurls=\fP\fINUMMER\fP Maximale Anzahl von URLs die geprüft werden. Neue URLs werden nicht angenommen nachdem die angegebene Anzahl von URLs geprüft wurde. Kommandozeilenoption: none .TP \fBmaxrequestspersecond=\fP\fINUMMER\fP Limit the maximum number of HTTP requests per second to one host. The average number of requests per second is approximately one third of the maximum. Values less than 1 and at least 0.001 can be used. To use values greater than 10, the HTTP server must return a \fBLinkChecker\fP response header. The default is 10. Command line option: none .TP \fBrobotstxt=\fP[\fB0\fP|\fB1\fP] When using http, fetch robots.txt, and confirm whether each URL should be accessed before checking. The default is to use robots.txt files. Command line option: \fI\%\-\-no\-robots\fP .TP \fBallowedschemes=\fP\fINAME\fP[\fB,\fP\fINAME\fP\&...] Allowed URL schemes as comma\-separated list. Command line option: none .TP \fBresultcachesize=\fP\fINUMBER\fP Set the result cache size. The default is 100 000 URLs. Command line option: none .UNINDENT .SS filtering .INDENT 0.0 .TP \fBignore=\fP\fIREGEX\fP (\fI\%MULTILINE\fP) Prüfe lediglich die Syntax von URLs, welche dem angegebenen regulären Ausdruck entsprechen. Kommandozeilenoption: \fI\%\-\-ignore\-url\fP .TP \fBignorewarnings=\fP\fINAME\fP[\fB,\fP\fINAME\fP\&...] Ignore the comma\-separated list of warnings. See \fI\%WARNINGS\fP for the list of supported warnings. Messages are logged as information. Command line option: none .TP \fBignorewarningsforurls=\fP\fIURL_REGEX\fP [\fINAME_REGEX\fP] (\fI\%MULTILINE\fP) Specify regular expressions to ignore warnings for matching URLs, one per line. On each line, you can specify a second regular expression, ensuring that only the warnings with names matching the second expression will be ignored for that URL. If the second expression is omitted, all warnings are ignored for that URL. .sp Default is to not ignore any warnings. See \fI\%WARNINGS\fP for the list of supported warnings. Messages are logged as information. Command line option: none .sp Example: .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C [filtering] ignorewarningsforurls= ^https://redirected\e.example\e.com ^http\-redirected .ft P .fi .UNINDENT .UNINDENT .INDENT 0.0 .TP \fBinternlinks=\fP\fIREGEX\fP Regulärer Ausdruck, um mehr URLs als interne Verknüpfungen hinzuzufügen. Standard ist dass URLs der Kommandozeile als intern gelten. Kommandozeilenoption: none .TP \fBnofollow=\fP\fIREGEX\fP (\fI\%MULTILINE\fP) Prüfe URLs die auf den regulären Ausdruck zutreffen, aber führe keine Rekursion durch. Kommandozeilenoption: \fI\%\-\-no\-follow\-url\fP .TP \fBcheckextern=\fP[\fB0\fP|\fB1\fP] Check external links. Default is to check internal links only. Command line option: \fI\%\-\-check\-extern\fP .UNINDENT .SS authentication .INDENT 0.0 .TP \fBentry=\fP\fIREGEX\fP \fIBENUTZER\fP [\fIPASSWORT\fP] (\fI\%MULTILINE\fP) Provide individual username/password pairs for different links. In addition to a single login page specified with \fBloginurl\fP multiple FTP and HTTP (Basic Authentication) links are supported. Entries are a triple (URL regex, username, password) or a tuple (URL regex, username), where the entries are separated by whitespace. The password is optional and if missing it has to be entered at the commandline. If the regular expression matches the checked URL, the given username/password pair is used for authentication. The command line options \fI\%\-u\fP and \fI\%\-p\fP match every link and therefore override the entries given here. The first match wins. Command line option: \fI\%\-u\fP, \fI\%\-p\fP .TP \fBloginurl=\fP\fIURL\fP The URL of a login page to be visited before link checking. The page is expected to contain an HTML form to collect credentials and submit them to the address in its action attribute using an HTTP POST request. The name attributes of the input elements of the form and the values to be submitted need to be available (see \fBentry\fP for an explanation of username and password values). .TP \fBloginuserfield=\fP\fISTRING\fP Der Name für das Benutzer CGI\-Feld. Der Standardname ist \fBlogin\fP\&. .TP \fBloginpasswordfield=\fP\fISTRING\fP Der Name für das Passwort CGI\-Feld. Der Standardname ist \fBpassword\fP\&. .TP \fBloginextrafields=\fP\fINAME\fP\fB:\fP\fIWERT\fP (\fI\%MULTILINE\fP) Optionally the name attributes of any additional input elements and the values to populate them with. Note that these are submitted without checking whether matching input elements exist in the HTML form. .UNINDENT .SS output .SS URL checking results .INDENT 0.0 .TP \fBfileoutput=\fP\fITYPE\fP[\fB,\fP\fITYPE\fP\&...] Output to a file \fBlinkchecker\-out.\fP\fITYPE\fP, or \fB$XDG_DATA_HOME/linkchecker/failures\fP for the \fBfailures\fP output type. Valid file output types are \fBtext\fP, \fBhtml\fP, \fBsql\fP, \fBcsv\fP, \fBgml\fP, \fBdot\fP, \fBxml\fP, \fBnone\fP or \fBfailures\fP\&. Default is no file output. The various output types are documented below. Note that you can suppress all console output with \fBoutput=none\fP\&. Command line option: \fI\%\-\-file\-output\fP .TP \fBlog=\fP\fITYPE\fP[\fB/\fP\fIENCODING\fP] Specify the console output type as \fBtext\fP, \fBhtml\fP, \fBsql\fP, \fBcsv\fP, \fBgml\fP, \fBdot\fP, \fBxml\fP, \fBnone\fP or \fBfailures\fP\&. Default type is \fBtext\fP\&. The various output types are documented below. The \fIENCODING\fP specifies the output encoding, the default is that of your locale. Valid encodings are listed at \X'tty: link https://docs.python.org/library/codecs.html#standard-encodings'\fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\X'tty: link'\&. Command line option: \fI\%\-\-output\fP .TP \fBverbose=\fP[\fB0\fP|\fB1\fP] If set log all checked URLs once, overriding \fBwarnings\fP\&. Default is to log only errors and warnings. Command line option: \fI\%\-\-verbose\fP .TP \fBwarnings=\fP[\fB0\fP|\fB1\fP] Falls gesetzt, gebe keine Warnungen aus. Standard ist die Ausgabe von Warnungen. Kommandozeilenoption: \fI\%\-\-verbose\fP .TP \fBignoreerrors=\fP\fIURL_REGEX\fP [\fIMESSAGE_REGEX\fP] (\fI\%MULTILINE\fP) Specify regular expressions to ignore errors for matching URLs, one per line. A second regular expression can be specified per line to only ignore matching error messages per corresponding URL. If the second expression is omitted, all errors are ignored. In contrast to \fI\%filtering\fP, this happens \fIafter\fP checking, which allows checking URLs despite certain expected and tolerable errors. Default is to not ignore any errors. Example: .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C [output] ignoreerrors= ^https://deprecated\e.example\e.com ^410 Gone # ignore all errors (no second expression), also for syntax check: ^mailto:.*@example\e.com$ .ft P .fi .UNINDENT .UNINDENT .SS Progress updates .INDENT 0.0 .TP \fBstatus=\fP[\fB0\fP|\fB1\fP] Control printing URL checker status messages. Default is 1. Command line option: \fI\%\-\-no\-status\fP .UNINDENT .SS Application .INDENT 0.0 .TP \fBdebug=\fP\fISTRING\fP[\fB,\fP\fISTRING\fP\&...] Print debugging output for the given logger. Available debug loggers are \fBcmdline\fP, \fBchecking\fP, \fBcache\fP, \fBplugin\fP and \fBall\fP\&. \fBall\fP is an alias for all available loggers. Command line option: \fI\%\-\-debug\fP .UNINDENT .SS Quiet .INDENT 0.0 .TP \fBquiet=\fP[\fB0\fP|\fB1\fP] If set, operate quiet. An alias for \fBlog=none\fP that also hides application information messages. This is only useful with \fBfileoutput\fP, else no results will be output. Command line option: \fI\%\-\-quiet\fP .UNINDENT .SH AUSGABETYPEN .SS text .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP Gebe Dateiname für Textausgabe an. Standard Dateiname ist \fBlinkchecker\-out.txt\fP\&. Kommandozeilenoption: \fI\%\-\-file\-output\fP .TP \fBparts=\fP\fISTRING\fP Kommagetrennte Liste von Teilen, die ausgegeben werden sollen. Siehe \fI\%LOGGER PARTS\fP weiter unten. Kommandozeilenoption: none .TP \fBencoding=\fP\fISTRING\fP Valid encodings are listed in \X'tty: link https://docs.python.org/library/codecs.html#standard-encodings'\fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\X'tty: link'\&. Default encoding is the system default locale encoding. .TP \fBwraplength=\fP\fINUMBER\fP The number of characters at which to wrap each message line. The default is 65. Command line option: none .TP .B \fIcolor*\fP Farbwerte für die verschiedenen Ausgabeteile. Syntax ist \fIcolor\fP oder \fItype\fP\fB;\fP\fIcolor\fP\&. Der \fItype\fP kann \fBbold\fP, \fBlight\fP, \fBblink\fP> oder \fBinvert\fP sein. Die \fIcolor\fP kann \fBdefault\fP, \fBblack\fP, \fBred\fP, \fBgreen\fP, \fByellow\fP, \fBblue\fP, \fBpurple\fP, \fBcyan\fP, \fBwhite\fP, \fBBlack\fP, \fBRed\fP, \fBGreen\fP, \fBYellow\fP, \fBBlue\fP, \fBPurple\fP, \fBCyan\fP oder \fBWhite\fP sein. Kommandozeilenoption: none .TP \fBcolorparent=\fP\fISTRING\fP Setze Farbe des Vaters. Standard ist \fBwhite\fP\&. .TP \fBcolorurl=\fP\fISTRING\fP Setze URL Farbe. Standard ist \fBdefault\fP\&. .TP \fBcolorname=\fP\fISTRING\fP Setze Namensfarbe. Standard ist \fBdefault\fP\&. .TP \fBcolorreal=\fP\fISTRING\fP Setze Farbe für tatsächliche URL. Default ist \fBcyan\fP\&. .TP \fBcolorbase=\fP\fISTRING\fP Setzt Basisurl Farbe. Standard ist \fBpurple\fP\&. .TP \fBcolorvalid=\fP\fISTRING\fP Setze gültige Farbe. Standard ist \fBbold;green\fP\&. .TP \fBcolorinvalid=\fP\fISTRING\fP Setze ungültige Farbe. Standard ist \fBbold;red\fP\&. .TP \fBcolorinfo=\fP\fISTRING\fP Setzt Informationsfarbe. Standard ist \fBdefault\fP\&. .TP \fBcolorwarning=\fP\fISTRING\fP Setze Warnfarbe. Standard ist \fBbold;yellow\fP\&. .TP \fBcolordltime=\fP\fISTRING\fP Setze Downloadzeitfarbe. Standard ist \fBdefault\fP\&. .TP \fBcolorreset=\fP\fISTRING\fP Setze Reset Farbe. Standard ist \fBdefault\fP\&. .UNINDENT .SS gml .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBparts=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBencoding=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .UNINDENT .SS dot .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBparts=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBencoding=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .UNINDENT .SS csv .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBparts=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBencoding=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBseparator=\fP\fICHAR\fP Set CSV separator. Default is a semicolon (\fB;\fP). .TP \fBquotechar=\fP\fICHAR\fP Setze CSV Quotezeichen. Standard ist das doppelte Anführungszeichen (\fB\(dq\fP). .TP \fBdialect=\fP\fISTRING\fP Controls the output formatting. See \X'tty: link https://docs.python.org/3/library/csv.html#csv.Dialect'\fI\%https://docs.python.org/3/library/csv.html#csv.Dialect\fP\X'tty: link'\&. Default is \fBexcel\fP\&. .UNINDENT .SS sql .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBparts=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBencoding=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBdbname=\fP\fISTRING\fP Setze Datenbankname zum Speichern. Standard ist \fBlinksdb\fP\&. .TP \fBseparator=\fP\fICHAR\fP Setze SQL Kommandotrennzeichen. Standard ist ein Strichpunkt (\fB;\fP). .UNINDENT .SS html .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBparts=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBencoding=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBcolorbackground=\fP\fICOLOR\fP Setze HTML Hintergrundfarbe. Standard ist \fB#fff7e5\fP\&. .TP \fBcolorurl=\fP Setze HTML URL Farbe. Standard ist \fB#dcd5cf\fP\&. .TP \fBcolorborder=\fP Setze HTML Rahmenfarbe. Standard ist \fB#000000\fP\&. .TP \fBcolorlink=\fP Setze HTML Verknüpfungsfarbe. Standard ist \fB#191c83\fP\&. .TP \fBcolorwarning=\fP Setze HTML Warnfarbe. Standard ist \fB#e0954e\fP\&. .TP \fBcolorerror=\fP Setze HTML Fehlerfarbe. Standard ist \fB#db4930\fP\&. .TP \fBcolorok=\fP Setze HTML Gültigkeitsfarbe. Standard ist \fB#3ba557\fP\&. .UNINDENT .SS failures .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBencoding=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .UNINDENT .SS xml .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBparts=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBencoding=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .UNINDENT .SS gxml .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBparts=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBencoding=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .UNINDENT .SS sitemap .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBparts=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBencoding=\fP\fISTRING\fP Siehe \fI\%[text]\fP Sektion weiter oben. .TP \fBpriority=\fP\fINUMMER\fP Eine Nummer zwischen 0.0 und 1.0, welche die Priorität festlegt. Die Standardpriorität für die erste URL ist 1.0, für alle Kind\-URLs ist sie 0.5. .TP \fBfrequency=\fP[\fBalways\fP|\fBhourly\fP|\fBdaily\fP|\fBweekly\fP|\fBmonthly\fP|\fByearly\fP|\fBnever\fP] How frequently pages are changing. Default is \fBdaily\fP\&. .UNINDENT .SH AUSGABE PARTS .INDENT 0.0 .TP \fBall\fP for all parts .TP \fBid\fP a unique ID for each logentry .TP \fBrealurl\fP the full url link .TP \fBresult\fP valid or invalid, with messages .TP \fBextern\fP 1 or 0, only in some logger types reported .TP \fBbase\fP base href=... .TP \fBname\fP name and \(dqname\(dq .TP \fBparenturl\fP if any .TP \fBinfo\fP some additional info, e.g. FTP welcome messages .TP \fBwarning\fP warnings .TP \fBdltime\fP download time .TP \fBchecktime\fP check time .TP \fBurl\fP the original url name, can be relative .TP \fBintro\fP the blurb at the beginning, \(dqstarting at ...\(dq .TP \fBoutro\fP the blurb at the end, \(dqfound x errors ...\(dq .UNINDENT .SH MULTILINE .sp Einige Optionen können mehrere Zeilen lang sein. Jede Zeile muss dafür eingerückt werden. Zeilen die mit einer Raute (\fB#\fP) beginnen werden ignoriert, müssen aber eingerückt sein. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ignore= lconline bookmark # a comment ^mailto: .ft P .fi .UNINDENT .UNINDENT .SH BEISPIEL .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C [output] log=html [checking] threads=5 [filtering] ignorewarnings=http\-moved\-permanent .ft P .fi .UNINDENT .UNINDENT .SH PLUGINS .sp All plugins have a separate section. If the section appears in the configuration file the plugin is enabled. Some plugins read extra options in their section. .SS AnchorCheck .sp Checks validity of HTML anchors. When checking local files, URLs with anchors that link to directories e.g. \(dqexample/#anchor\(dq are not supported. There is no such limitation when using http(s). .SS LocationInfo .sp Adds the country and if possible city name of the URL host as info. Needs GeoIP or pygeoip and a local country or city lookup DB installed. .SS RegexCheck .sp Definieren Sie einen regulären Ausdruck der eine Warnung ausgibt falls er auf den Inhalt einer geprüften URL zutrifft. Dies gilt nur für gültige Seiten deren Inhalt wir bekommen können. .INDENT 0.0 .TP \fBwarningregex=\fP\fIREGEX\fP Use this to check for pages that contain some form of error message, for example \(dqThis page has moved\(dq or \(dqOracle Application error\(dq. \fIREGEX\fP should be unquoted. .sp Man beachte, dass mehrere Werte in dem regulären Ausdruck kombiniert werden können, zum Beispiel \(dq(Diese Seite ist umgezogen|Oracle Applikationsfehler)\(dq. .UNINDENT .SS SslCertificateCheck .sp Check SSL certificate expiration date. Only internal https: links will be checked. A domain will only be checked once to avoid duplicate warnings. .INDENT 0.0 .TP \fBsslcertwarndays=\fP\fINUMMER\fP Configures the expiration warning time in days. .UNINDENT .SS HtmlSyntaxCheck .sp Check the syntax of HTML pages by submitting their URLs to the online W3C HTML validator. If a page URL is not accessible to the validator no check is performed and no warning given. See \X'tty: link https://validator.w3.org/docs/api.html'\fI\%https://validator.w3.org/docs/api.html\fP\X'tty: link'\&. .sp \fBBEMERKUNG:\fP .INDENT 0.0 .INDENT 3.5 The HtmlSyntaxCheck plugin is currently broken and is disabled. .UNINDENT .UNINDENT .SS HttpHeaderInfo .sp Print HTTP headers in URL info. .INDENT 0.0 .TP \fBprefixes=\fP\fIprefix1\fP[,*prefix2*]... List of comma separated header prefixes. For example to display all HTTP headers that start with \(dqX\-\(dq. .UNINDENT .SS CssSyntaxCheck .sp Check the syntax of CSS stylesheets by submitting their URLs to the online W3C CSS validator. If a stylesheet URL is not accessible to the validator no check is performed and no warning given. See \X'tty: link https://jigsaw.w3.org/css-validator/manual.html#expert'\fI\%https://jigsaw.w3.org/css\-validator/manual.html#expert\fP\X'tty: link'\&. .SS VirusCheck .sp Checks the page content for virus infections with clamav. A local clamav daemon must be installed. .INDENT 0.0 .TP \fBclamavconf=\fP\fIDateiname\fP Dateiname von \fBclamd.conf\fP Konfigurationsdatei. .UNINDENT .SS PdfParser .sp Parse PDF files for URLs to check. Needs the \X'tty: link https://pypi.org/project/pdfminer.six/'\fI\%pdfminer.six\fP\X'tty: link' Python package installed. .SS WordParser .sp Parse Word files for URLs to check. Needs the \X'tty: link https://pypi.org/project/pywin32/'\fI\%pywin32\fP\X'tty: link' Python extension installed. .SS MarkdownCheck .sp Parse Markdown files for URLs to check. .INDENT 0.0 .TP \fBfilename_re=\fP\fIREGEX\fP Regular expression matching the names of Markdown files. .UNINDENT .SH WARNUNGEN .sp The following warnings are recognized by \fBignorewarnings\fP and \fBignorewarningsforurls\fP: .INDENT 0.0 .TP \fBfile\-anchorcheck\-directory\fP A local directory with an anchor, not supported by AnchorCheck. .TP \fBfile\-missing\-slash\fP Der file: URL fehlt ein abschließender Schrägstrich. .TP \fBfile\-system\-path\fP Der file: Pfad ist nicht derselbe wie der Systempfad. .TP \fBftp\-missing\-slash\fP Der ftp: URL fehlt ein abschließender Schrägstrich. .TP \fBhttp\-cookie\-store\-error\fP Ein Fehler trat auf während des Speicherns eines Cookies. .TP \fBhttp\-empty\-content\fP Die URL besitzt keinen Inhalt. .TP \fBhttp\-rate\-limited\fP Too many HTTP requests. .TP \fBhttp\-redirected\fP Redirected to a different URL. .TP \fBmail\-no\-mx\-host\fP Der MX Mail\-Rechner konnte nicht gefunden werden. .TP \fBurl\-content\-size\-zero\fP Der URL Inhaltsgrößenangabe ist Null. .TP \fBurl\-content\-too\-large\fP Der URL Inhalt ist zu groß. .TP \fBurl\-content\-type\-unparseable\fP The URL content type is not parseable. .TP \fBurl\-effective\-url\fP Die effektive URL unterscheidet sich vom Original. .TP \fBurl\-error\-getting\-content\fP Konnte den Inhalt der URL nicht bekommen. .TP \fBurl\-obfuscated\-ip\fP Die IP\-Adresse ist verschleiert. .TP \fBurl\-whitespace\fP Die URL %(url)s enthält Leerzeichen am Anfang oder Ende. .UNINDENT .SH SIEHE AUCH .sp \fB\fI\%linkchecker(1)\fP\fP .SH AUTHOR Bastian Kleineidam .SH COPYRIGHT 2000-2016 Bastian Kleineidam, 2010-2024 LinkChecker Authors .\" Generated by docutils manpage writer. . linkchecker-10.5.0/doc/man/en/000077500000000000000000000000001466565367000160235ustar00rootroot00000000000000linkchecker-10.5.0/doc/man/en/linkchecker.1000066400000000000000000000447071466565367000204030ustar00rootroot00000000000000.\" Man page generated from reStructuredText. . . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .TH "LINKCHECKER" "1" "August 27, 2024" "10.4.0.post49+g7cf5037e" "LinkChecker" .SH NAME linkchecker \- command line client to check HTML documents and websites for broken links .SH SYNOPSIS .sp \fBlinkchecker\fP [\fIoptions\fP] [\fIfile\-or\-url\fP]... .SH DESCRIPTION .sp LinkChecker features .INDENT 0.0 .IP \(bu 2 recursive and multithreaded checking .IP \(bu 2 output in colored or normal text, HTML, SQL, CSV, XML or a sitemap graph in different formats .IP \(bu 2 support for HTTP/1.1, HTTPS, FTP, mailto: and local file links .IP \(bu 2 restriction of link checking with URL filters .IP \(bu 2 proxy support .IP \(bu 2 username/password authorization for HTTP and FTP .IP \(bu 2 support for robots.txt exclusion protocol .IP \(bu 2 support for Cookies .IP \(bu 2 support for HTML5 .IP \(bu 2 Antivirus check .IP \(bu 2 a command line and web interface .UNINDENT .SH EXAMPLES .sp The most common use checks the given domain recursively: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ linkchecker http://www.example.com/ .ft P .fi .UNINDENT .UNINDENT .sp Beware that this checks the whole site which can have thousands of URLs. Use the \fI\%\-r\fP option to restrict the recursion depth. .sp Don\(aqt check URLs with \fB/secret\fP in its name. All other links are checked as usual: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ linkchecker \-\-ignore\-url=/secret mysite.example.com .ft P .fi .UNINDENT .UNINDENT .sp Checking a local HTML file on Unix: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ linkchecker ../bla.html .ft P .fi .UNINDENT .UNINDENT .sp Checking a local HTML file on Windows: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C C:\e> linkchecker c:empest.html .ft P .fi .UNINDENT .UNINDENT .sp You can skip the \fBhttp://\fP url part if the domain starts with \fBwww.\fP: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ linkchecker www.example.com .ft P .fi .UNINDENT .UNINDENT .sp You can skip the \fBftp://\fP url part if the domain starts with \fBftp.\fP: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ linkchecker \-r0 ftp.example.com .ft P .fi .UNINDENT .UNINDENT .sp Generate a sitemap graph and convert it with the graphviz dot utility: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ linkchecker \-odot \-v www.example.com | dot \-Tps > sitemap.ps .ft P .fi .UNINDENT .UNINDENT .SH OPTIONS .SS General options .INDENT 0.0 .TP .B \-f FILENAME, \-\-config=FILENAME Use FILENAME as configuration file. By default LinkChecker uses $XDG_CONFIG_HOME/linkchecker/linkcheckerrc. .UNINDENT .INDENT 0.0 .TP .B \-h, \-\-help Help me! Print usage information for this program. .UNINDENT .INDENT 0.0 .TP .B \-t NUMBER, \-\-threads=NUMBER Generate no more than the given number of threads. Default number of threads is 10. To disable threading specify a non\-positive number. .UNINDENT .INDENT 0.0 .TP .B \-V, \-\-version Print version and exit. .UNINDENT .INDENT 0.0 .TP .B \-\-list\-plugins Print available check plugins and exit. .UNINDENT .SS Output options .SS URL checking results .INDENT 0.0 .TP .B \-F TYPE[/ENCODING][/FILENAME], \-\-file\-output=TYPE[/ENCODING][/FILENAME] Output to a file linkchecker\-out.TYPE, $XDG_DATA_HOME/linkchecker/failures for the failures output type, or FILENAME if specified. The ENCODING specifies the output encoding, the default is that of your locale. Valid encodings are listed at \X'tty: link https://docs.python.org/library/codecs.html#standard-encodings'\fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\X'tty: link'\&. The FILENAME and ENCODING parts of the none output type will be ignored, else if the file already exists, it will be overwritten. You can specify this option more than once. Valid file output TYPEs are text, html, sql, csv, gml, dot, xml, sitemap, none or failures. Default is no file output. The various output types are documented below. Note that you can suppress all console output with the option \fI\%\-o\fP \fInone\fP\&. .UNINDENT .INDENT 0.0 .TP .B \-\-no\-warnings Don\(aqt log warnings. Default is to log warnings. .UNINDENT .INDENT 0.0 .TP .B \-o TYPE[/ENCODING], \-\-output=TYPE[/ENCODING] Specify the console output type as text, html, sql, csv, gml, dot, xml, sitemap, none or failures. Default type is text. The various output types are documented below. The ENCODING specifies the output encoding, the default is that of your locale. Valid encodings are listed at \X'tty: link https://docs.python.org/library/codecs.html#standard-encodings'\fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\X'tty: link'\&. .UNINDENT .INDENT 0.0 .TP .B \-v, \-\-verbose Log all checked URLs, overriding \fI\%\-\-no\-warnings\fP\&. Default is to log only errors and warnings. .UNINDENT .SS Progress updates .INDENT 0.0 .TP .B \-\-no\-status Do not print URL check status messages. .UNINDENT .SS Application .INDENT 0.0 .TP .B \-D STRING, \-\-debug=STRING Print debugging output for the given logger. Available debug loggers are cmdline, checking, cache, plugin and all. all is an alias for all available loggers. This option can be given multiple times to debug with more than one logger. .UNINDENT .SS Quiet .INDENT 0.0 .TP .B \-q, \-\-quiet Quiet operation, an alias for \fI\%\-o\fP \fInone\fP that also hides application information messages. This is only useful with \fI\%\-F\fP, else no results will be output. .UNINDENT .SS Checking options .INDENT 0.0 .TP .B \-\-cookiefile=FILENAME Use initial cookie data read from a file. The cookie data format is explained below. .UNINDENT .INDENT 0.0 .TP .B \-\-check\-extern Check external URLs. .UNINDENT .INDENT 0.0 .TP .B \-\-ignore\-url=REGEX URLs matching the given regular expression will only be syntax checked. This option can be given multiple times. See section \fI\%REGULAR EXPRESSIONS\fP for more info. .UNINDENT .INDENT 0.0 .TP .B \-\-no\-follow\-url=REGEX Check but do not recurse into URLs matching the given regular expression. This option can be given multiple times. See section \fI\%REGULAR EXPRESSIONS\fP for more info. .UNINDENT .INDENT 0.0 .TP .B \-\-no\-robots Check URLs regardless of any robots.txt files. .UNINDENT .INDENT 0.0 .TP .B \-p, \-\-password Read a password from console and use it for HTTP and FTP authorization. For FTP the default password is anonymous@. For HTTP there is no default password. See also \fI\%\-u\fP\&. .UNINDENT .INDENT 0.0 .TP .B \-r NUMBER, \-\-recursion\-level=NUMBER Check recursively all links up to given depth. A negative depth will enable infinite recursion. Default depth is infinite. .UNINDENT .INDENT 0.0 .TP .B \-\-timeout=NUMBER Set the timeout for connection attempts in seconds. The default timeout is 60 seconds. .UNINDENT .INDENT 0.0 .TP .B \-u STRING, \-\-user=STRING Try the given username for HTTP and FTP authorization. For FTP the default username is anonymous. For HTTP there is no default username. See also \fI\%\-p\fP\&. .UNINDENT .INDENT 0.0 .TP .B \-\-user\-agent=STRING Specify the User\-Agent string to send to the HTTP server, for example \(dqMozilla/4.0\(dq. The default is \(dqLinkChecker/X.Y\(dq where X.Y is the current version of LinkChecker. .UNINDENT .SS Input options .INDENT 0.0 .TP .B \-\-stdin Read from stdin a list of white\-space separated URLs to check. .UNINDENT .INDENT 0.0 .TP .B FILE\-OR\-URL The location to start checking with. A file can be a simple list of URLs, one per line, if the first line is \(dq# LinkChecker URL list\(dq. .UNINDENT .SH CONFIGURATION FILES .sp Configuration files can specify all options above. They can also specify some options that cannot be set on the command line. See \fB\fI\%linkcheckerrc(5)\fP\fP for more info. .SH OUTPUT TYPES .sp Note that by default only errors and warnings are logged. You should use the option \fI\%\-\-verbose\fP to get the complete URL list, especially when outputting a sitemap graph format. .INDENT 0.0 .TP \fBtext\fP Standard text logger, logging URLs in keyword: argument fashion. .TP \fBhtml\fP Log URLs in keyword: argument fashion, formatted as HTML. Additionally has links to the referenced pages. Invalid URLs have HTML and CSS syntax check links appended. .TP \fBcsv\fP Log check result in CSV format with one URL per line. .TP \fBgml\fP Log parent\-child relations between linked URLs as a GML sitemap graph. .TP \fBdot\fP Log parent\-child relations between linked URLs as a DOT sitemap graph. .TP \fBgxml\fP Log check result as a GraphXML sitemap graph. .TP \fBxml\fP Log check result as machine\-readable XML. .TP \fBsitemap\fP Log check result as an XML sitemap whose protocol is documented at \X'tty: link https://www.sitemaps.org/protocol.html'\fI\%https://www.sitemaps.org/protocol.html\fP\X'tty: link'\&. .TP \fBsql\fP Log check result as SQL script with INSERT commands. An example script to create the initial SQL table is included as create.sql. .TP \fBfailures\fP Suitable for cron jobs. Logs the check result into a file \fB$XDG_DATA_HOME/linkchecker/failures\fP which only contains entries with invalid URLs and the number of times they have failed. .TP \fBnone\fP Logs nothing. Suitable for debugging or checking the exit code. .UNINDENT .SH REGULAR EXPRESSIONS .sp LinkChecker accepts Python regular expressions. See \X'tty: link https://docs.python.org/howto/regex.html'\fI\%https://docs.python.org/howto/regex.html\fP\X'tty: link' for an introduction. An addition is that a leading exclamation mark negates the regular expression. .SH COOKIE FILES .sp A cookie file contains standard HTTP header (RFC 2616) data with the following possible names: .INDENT 0.0 .TP \fBHost\fP (required) Sets the domain the cookies are valid for. .TP \fBPath\fP (optional) Gives the path the cookies are value for; default path is \fB/\fP\&. .TP \fBSet\-cookie\fP (required) Set cookie name/value. Can be given more than once. .UNINDENT .sp Multiple entries are separated by a blank line. The example below will send two cookies to all URLs starting with \fBhttp://example.com/hello/\fP and one to all URLs starting with \fBhttps://example.org/\fP: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Host: example.com Path: /hello Set\-cookie: ID=\(dqsmee\(dq Set\-cookie: spam=\(dqegg\(dq .ft P .fi .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Host: example.org Set\-cookie: baggage=\(dqelitist\(dq; comment=\(dqhologram\(dq .ft P .fi .UNINDENT .UNINDENT .SH PROXY SUPPORT .sp To use a proxy on Unix or Windows set the \fI\%http_proxy\fP or \fI\%https_proxy\fP environment variables to the proxy URL. The URL should be of the form \fBhttp://\fP[\fIuser\fP\fB:\fP\fIpass\fP\fB@\fP]\fIhost\fP[\fB:\fP\fIport\fP]. LinkChecker also detects manual proxy settings of Internet Explorer under Windows systems. On a Mac use the Internet Config to select a proxy. You can also set a comma\-separated domain list in the \fI\%no_proxy\fP environment variable to ignore any proxy settings for these domains. The \fI\%curl_ca_bundle\fP environment variable can be used to identify an alternative certificate bundle to be used with an HTTPS proxy. .sp Setting a HTTP proxy on Unix for example looks like this: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ export http_proxy=\(dqhttp://proxy.example.com:8080\(dq .ft P .fi .UNINDENT .UNINDENT .sp Proxy authentication is also supported: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ export http_proxy=\(dqhttp://user1:mypass@proxy.example.org:8081\(dq .ft P .fi .UNINDENT .UNINDENT .sp Setting a proxy on the Windows command prompt: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C C:\e> set http_proxy=http://proxy.example.com:8080 .ft P .fi .UNINDENT .UNINDENT .SH PERFORMED CHECKS .sp All URLs have to pass a preliminary syntax test. Minor quoting mistakes will issue a warning, all other invalid syntax issues are errors. After the syntax check passes, the URL is queued for connection checking. All connection check types are described below. .INDENT 0.0 .TP HTTP links (\fBhttp:\fP, \fBhttps:\fP) After connecting to the given HTTP server the given path or query is requested. All redirections are followed, and if user/password is given it will be used as authorization when necessary. All final HTTP status codes other than 2xx are errors. .sp HTML page contents are checked for recursion. .TP Local files (\fBfile:\fP) A regular, readable file that can be opened is valid. A readable directory is also valid. All other files, for example device files, unreadable or non\-existing files are errors. .sp HTML or other parseable file contents are checked for recursion. .TP Mail links (\fBmailto:\fP) A mailto: link eventually resolves to a list of email addresses. If one address fails, the whole list will fail. For each mail address we check the following things: .INDENT 7.0 .IP 1. 3 Check the address syntax, both the parts before and after the @ sign. .IP 2. 3 Look up the MX DNS records. If we found no MX record, print an error. .IP 3. 3 Check if one of the mail hosts accept an SMTP connection. Check hosts with higher priority first. If no host accepts SMTP, we print a warning. .IP 4. 3 Try to verify the address with the VRFY command. If we got an answer, print the verified address as an info. .UNINDENT .TP FTP links (\fBftp:\fP) For FTP links we do: .INDENT 7.0 .IP 1. 3 connect to the specified host .IP 2. 3 try to login with the given user and password. The default user is \fBanonymous\fP, the default password is \fBanonymous@\fP\&. .IP 3. 3 try to change to the given directory .IP 4. 3 list the file with the NLST command .UNINDENT .TP Unsupported links (\fBjavascript:\fP, etc.) An unsupported link will only print a warning. No further checking will be made. .sp The complete list of recognized, but unsupported links can be found in the \X'tty: link https://github.com/linkchecker/linkchecker/blob/master/linkcheck/checker/unknownurl.py'\fI\%linkcheck/checker/unknownurl.py\fP\X'tty: link' source file. The most prominent of them should be JavaScript links. .UNINDENT .SH SITEMAPS .sp Sitemaps are parsed for links to check and can be detected either from a sitemap entry in a robots.txt, or when passed as a \fI\%FILE\-OR\-URL\fP argument in which case detection requires the urlset/sitemapindex tag to be within the first 70 characters of the sitemap. Compressed sitemap files are not supported. .SH PLUGINS .sp There are two plugin types: connection and content plugins. Connection plugins are run after a successful connection to the URL host. Content plugins are run if the URL type has content (mailto: URLs have no content for example) and if the check is not forbidden (ie. by HTTP robots.txt). Use the option \fI\%\-\-list\-plugins\fP for a list of plugins and their documentation. All plugins are enabled via the \fB\fI\%linkcheckerrc(5)\fP\fP configuration file. .SH RECURSION .sp Before descending recursively into a URL, it has to fulfill several conditions. They are checked in this order: .INDENT 0.0 .IP 1. 3 A URL must be valid. .IP 2. 3 A URL must be parseable. This currently includes HTML files, Opera bookmarks files, and directories. If a file type cannot be determined (for example it does not have a common HTML file extension, and the content does not look like HTML), it is assumed to be non\-parseable. .IP 3. 3 The URL content must be retrievable. This is usually the case except for example mailto: or unknown URL types. .IP 4. 3 The maximum recursion level must not be exceeded. It is configured with the \fI\%\-\-recursion\-level\fP option and is unlimited per default. .IP 5. 3 It must not match the ignored URL list. This is controlled with the \fI\%\-\-ignore\-url\fP option. .IP 6. 3 The Robots Exclusion Protocol must allow links in the URL to be followed recursively. This is checked by searching for a \(dqnofollow\(dq directive in the HTML header data. .UNINDENT .sp Note that the directory recursion reads all files in that directory, not just a subset like \fBindex.htm\fP\&. .SH NOTES .sp URLs on the commandline starting with \fBftp.\fP are treated like \fBftp://ftp.\fP, URLs starting with \fBwww.\fP are treated like \fBhttp://www.\fP\&. You can also give local files as arguments. If you have your system configured to automatically establish a connection to the internet (e.g. with diald), it will connect when checking links not pointing to your local host. Use the \fI\%\-\-ignore\-url\fP option to prevent this. .sp Javascript links are not supported. .sp If your platform does not support threading, LinkChecker disables it automatically. .sp You can supply multiple user/password pairs in a configuration file. .SH ENVIRONMENT .INDENT 0.0 .TP .B http_proxy specifies default HTTP proxy server .UNINDENT .INDENT 0.0 .TP .B https_proxy specifies default HTTPS proxy server .UNINDENT .INDENT 0.0 .TP .B curl_ca_bundle an alternative certificate bundle to be used with an HTTPS proxy .UNINDENT .INDENT 0.0 .TP .B no_proxy comma\-separated list of domains to not contact over a proxy server .UNINDENT .INDENT 0.0 .TP .B LC_MESSAGES, LANG, LANGUAGE specify output language .UNINDENT .SH RETURN VALUE .sp The return value is 2 when .INDENT 0.0 .IP \(bu 2 a program error occurred. .UNINDENT .sp The return value is 1 when .INDENT 0.0 .IP \(bu 2 invalid links were found or .IP \(bu 2 link warnings were found and warnings are enabled .UNINDENT .sp Else the return value is zero. .SH LIMITATIONS .sp LinkChecker consumes memory for each queued URL to check. With thousands of queued URLs the amount of consumed memory can become quite large. This might slow down the program or even the whole system. .SH FILES .sp \fB$XDG_CONFIG_HOME/linkchecker/linkcheckerrc\fP \- default configuration file .sp \fB$XDG_DATA_HOME/linkchecker/failures\fP \- default failures logger output filename .sp \fBlinkchecker\-out.\fP\fITYPE\fP \- default logger file output name .SH SEE ALSO .sp \fB\fI\%linkcheckerrc(5)\fP\fP .sp \X'tty: link https://docs.python.org/library/codecs.html#standard-encodings'\fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\X'tty: link' \- valid output encodings .sp \X'tty: link https://docs.python.org/howto/regex.html'\fI\%https://docs.python.org/howto/regex.html\fP\X'tty: link' \- regular expression documentation .SH AUTHOR Bastian Kleineidam .SH COPYRIGHT 2000-2016 Bastian Kleineidam, 2010-2024 LinkChecker Authors .\" Generated by docutils manpage writer. . linkchecker-10.5.0/doc/man/en/linkcheckerrc.5000066400000000000000000000550141466565367000207250ustar00rootroot00000000000000.\" Man page generated from reStructuredText. . . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .TH "LINKCHECKERRC" "5" "August 27, 2024" "10.4.0.post49+g7cf5037e" "LinkChecker" .SH NAME linkcheckerrc \- configuration file for LinkChecker .SH DESCRIPTION .sp \fBlinkcheckerrc\fP is the configuration file for LinkChecker. The file is written in an INI\-style format. The default file location is \fB$XDG_CONFIG_HOME/linkchecker/linkcheckerrc\fP or else \fB~/.config/linkchecker/linkcheckerrc\fP on Unix, \fB%HOMEPATH%\e.config\elinkchecker\elinkcheckerrc\fP on Windows systems. .SH SETTINGS .SS checking .INDENT 0.0 .TP \fBcookiefile=\fP\fIfilename\fP Read a file with initial cookie data. The cookie data format is explained in \fB\fI\%linkchecker(1)\fP\fP\&. Command line option: \fI\%\-\-cookiefile\fP .TP \fBdebugmemory=\fP[\fB0\fP|\fB1\fP] Write memory allocation statistics to a file on exit, requires \X'tty: link https://pypi.org/project/meliae/'\fI\%meliae\fP\X'tty: link'\&. The default is not to write the file. Command line option: none .TP \fBlocalwebroot=\fP\fISTRING\fP When checking absolute URLs inside local files, the given root directory is used as base URL. Note that the given directory must have URL syntax, so it must use a slash to join directories instead of a backslash. And the given directory must end with a slash. Command line option: none .TP \fBrecursionlevel=\fP\fINUMBER\fP Check recursively all links up to given depth. A negative depth will enable infinite recursion. Default depth is infinite. Command line option: \fI\%\-\-recursion\-level\fP .TP \fBthreads=\fP\fINUMBER\fP Generate no more than the given number of threads. Default number of threads is 10. To disable threading specify a non\-positive number. Command line option: \fI\%\-\-threads\fP .TP \fBtimeout=\fP\fINUMBER\fP Set the timeout for connection attempts in seconds. The default timeout is 60 seconds. Command line option: \fI\%\-\-timeout\fP .TP \fBaborttimeout=\fP\fINUMBER\fP Time to wait for checks to finish after the user aborts the first time (with Ctrl\-C or the abort button). The default abort timeout is 300 seconds. Command line option: none .TP \fBuseragent=\fP\fISTRING\fP Specify the User\-Agent string to send to the HTTP server, for example \(dqMozilla/4.0\(dq. The default is \(dqLinkChecker/X.Y\(dq where X.Y is the current version of LinkChecker. Command line option: \fI\%\-\-user\-agent\fP .TP \fBsslverify=\fP[\fB0\fP|\fB1\fP|\fIfilename\fP] If set to zero disables SSL certificate checking. If set to one (the default) enables SSL certificate checking with the provided CA certificate file. If a filename is specified, it will be used as the certificate file. Command line option: none .TP \fBmaxrunseconds=\fP\fINUMBER\fP Stop checking new URLs after the given number of seconds. Same as if the user stops (by hitting Ctrl\-C) after the given number of seconds. The default is not to stop until all URLs are checked. Command line option: none .TP \fBmaxfilesizedownload=\fP\fINUMBER\fP Files larger than NUMBER bytes will be ignored, without downloading anything if accessed over http and an accurate Content\-Length header was returned. No more than this amount of a file will be downloaded. The default is 5242880 (5 MB). Command line option: none .TP \fBmaxfilesizeparse=\fP\fINUMBER\fP Files larger than NUMBER bytes will not be parsed for links. The default is 1048576 (1 MB). Command line option: none .TP \fBmaxnumurls=\fP\fINUMBER\fP Maximum number of URLs to check. New URLs will not be queued after the given number of URLs is checked. The default is to queue and check all URLs. Command line option: none .TP \fBmaxrequestspersecond=\fP\fINUMBER\fP Limit the maximum number of HTTP requests per second to one host. The average number of requests per second is approximately one third of the maximum. Values less than 1 and at least 0.001 can be used. To use values greater than 10, the HTTP server must return a \fBLinkChecker\fP response header. The default is 10. Command line option: none .TP \fBrobotstxt=\fP[\fB0\fP|\fB1\fP] When using http, fetch robots.txt, and confirm whether each URL should be accessed before checking. The default is to use robots.txt files. Command line option: \fI\%\-\-no\-robots\fP .TP \fBallowedschemes=\fP\fINAME\fP[\fB,\fP\fINAME\fP\&...] Allowed URL schemes as comma\-separated list. Command line option: none .TP \fBresultcachesize=\fP\fINUMBER\fP Set the result cache size. The default is 100 000 URLs. Command line option: none .UNINDENT .SS filtering .INDENT 0.0 .TP \fBignore=\fP\fIREGEX\fP (\fI\%MULTILINE\fP) Only check syntax of URLs matching the given regular expressions. Command line option: \fI\%\-\-ignore\-url\fP .TP \fBignorewarnings=\fP\fINAME\fP[\fB,\fP\fINAME\fP\&...] Ignore the comma\-separated list of warnings. See \fI\%WARNINGS\fP for the list of supported warnings. Messages are logged as information. Command line option: none .TP \fBignorewarningsforurls=\fP\fIURL_REGEX\fP [\fINAME_REGEX\fP] (\fI\%MULTILINE\fP) Specify regular expressions to ignore warnings for matching URLs, one per line. On each line, you can specify a second regular expression, ensuring that only the warnings with names matching the second expression will be ignored for that URL. If the second expression is omitted, all warnings are ignored for that URL. .sp Default is to not ignore any warnings. See \fI\%WARNINGS\fP for the list of supported warnings. Messages are logged as information. Command line option: none .sp Example: .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C [filtering] ignorewarningsforurls= ^https://redirected\e.example\e.com ^http\-redirected .ft P .fi .UNINDENT .UNINDENT .INDENT 0.0 .TP \fBinternlinks=\fP\fIREGEX\fP Regular expression to add more URLs recognized as internal links. Default is that URLs given on the command line are internal. Command line option: none .TP \fBnofollow=\fP\fIREGEX\fP (\fI\%MULTILINE\fP) Check but do not recurse into URLs matching the given regular expressions. Command line option: \fI\%\-\-no\-follow\-url\fP .TP \fBcheckextern=\fP[\fB0\fP|\fB1\fP] Check external links. Default is to check internal links only. Command line option: \fI\%\-\-check\-extern\fP .UNINDENT .SS authentication .INDENT 0.0 .TP \fBentry=\fP\fIREGEX\fP \fIUSER\fP [\fIPASS\fP] (\fI\%MULTILINE\fP) Provide individual username/password pairs for different links. In addition to a single login page specified with \fBloginurl\fP multiple FTP and HTTP (Basic Authentication) links are supported. Entries are a triple (URL regex, username, password) or a tuple (URL regex, username), where the entries are separated by whitespace. The password is optional and if missing it has to be entered at the commandline. If the regular expression matches the checked URL, the given username/password pair is used for authentication. The command line options \fI\%\-u\fP and \fI\%\-p\fP match every link and therefore override the entries given here. The first match wins. Command line option: \fI\%\-u\fP, \fI\%\-p\fP .TP \fBloginurl=\fP\fIURL\fP The URL of a login page to be visited before link checking. The page is expected to contain an HTML form to collect credentials and submit them to the address in its action attribute using an HTTP POST request. The name attributes of the input elements of the form and the values to be submitted need to be available (see \fBentry\fP for an explanation of username and password values). .TP \fBloginuserfield=\fP\fISTRING\fP The name attribute of the username input element. Default: \fBlogin\fP\&. .TP \fBloginpasswordfield=\fP\fISTRING\fP The name attribute of the password input element. Default: \fBpassword\fP\&. .TP \fBloginextrafields=\fP\fINAME\fP\fB:\fP\fIVALUE\fP (\fI\%MULTILINE\fP) Optionally the name attributes of any additional input elements and the values to populate them with. Note that these are submitted without checking whether matching input elements exist in the HTML form. .UNINDENT .SS output .SS URL checking results .INDENT 0.0 .TP \fBfileoutput=\fP\fITYPE\fP[\fB,\fP\fITYPE\fP\&...] Output to a file \fBlinkchecker\-out.\fP\fITYPE\fP, or \fB$XDG_DATA_HOME/linkchecker/failures\fP for the \fBfailures\fP output type. Valid file output types are \fBtext\fP, \fBhtml\fP, \fBsql\fP, \fBcsv\fP, \fBgml\fP, \fBdot\fP, \fBxml\fP, \fBnone\fP or \fBfailures\fP\&. Default is no file output. The various output types are documented below. Note that you can suppress all console output with \fBoutput=none\fP\&. Command line option: \fI\%\-\-file\-output\fP .TP \fBlog=\fP\fITYPE\fP[\fB/\fP\fIENCODING\fP] Specify the console output type as \fBtext\fP, \fBhtml\fP, \fBsql\fP, \fBcsv\fP, \fBgml\fP, \fBdot\fP, \fBxml\fP, \fBnone\fP or \fBfailures\fP\&. Default type is \fBtext\fP\&. The various output types are documented below. The \fIENCODING\fP specifies the output encoding, the default is that of your locale. Valid encodings are listed at \X'tty: link https://docs.python.org/library/codecs.html#standard-encodings'\fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\X'tty: link'\&. Command line option: \fI\%\-\-output\fP .TP \fBverbose=\fP[\fB0\fP|\fB1\fP] If set log all checked URLs once, overriding \fBwarnings\fP\&. Default is to log only errors and warnings. Command line option: \fI\%\-\-verbose\fP .TP \fBwarnings=\fP[\fB0\fP|\fB1\fP] If set log warnings. Default is to log warnings. Command line option: \fI\%\-\-no\-warnings\fP .TP \fBignoreerrors=\fP\fIURL_REGEX\fP [\fIMESSAGE_REGEX\fP] (\fI\%MULTILINE\fP) Specify regular expressions to ignore errors for matching URLs, one per line. A second regular expression can be specified per line to only ignore matching error messages per corresponding URL. If the second expression is omitted, all errors are ignored. In contrast to \fI\%filtering\fP, this happens \fIafter\fP checking, which allows checking URLs despite certain expected and tolerable errors. Default is to not ignore any errors. Example: .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C [output] ignoreerrors= ^https://deprecated\e.example\e.com ^410 Gone # ignore all errors (no second expression), also for syntax check: ^mailto:.*@example\e.com$ .ft P .fi .UNINDENT .UNINDENT .SS Progress updates .INDENT 0.0 .TP \fBstatus=\fP[\fB0\fP|\fB1\fP] Control printing URL checker status messages. Default is 1. Command line option: \fI\%\-\-no\-status\fP .UNINDENT .SS Application .INDENT 0.0 .TP \fBdebug=\fP\fISTRING\fP[\fB,\fP\fISTRING\fP\&...] Print debugging output for the given logger. Available debug loggers are \fBcmdline\fP, \fBchecking\fP, \fBcache\fP, \fBplugin\fP and \fBall\fP\&. \fBall\fP is an alias for all available loggers. Command line option: \fI\%\-\-debug\fP .UNINDENT .SS Quiet .INDENT 0.0 .TP \fBquiet=\fP[\fB0\fP|\fB1\fP] If set, operate quiet. An alias for \fBlog=none\fP that also hides application information messages. This is only useful with \fBfileoutput\fP, else no results will be output. Command line option: \fI\%\-\-quiet\fP .UNINDENT .SH OUTPUT TYPES .SS text .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP Specify output filename for text logging. Default filename is \fBlinkchecker\-out.txt\fP\&. Command line option: \fI\%\-\-file\-output\fP .TP \fBparts=\fP\fISTRING\fP Comma\-separated list of parts that have to be logged. See \fI\%LOGGER PARTS\fP below. Command line option: none .TP \fBencoding=\fP\fISTRING\fP Valid encodings are listed in \X'tty: link https://docs.python.org/library/codecs.html#standard-encodings'\fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\X'tty: link'\&. Default encoding is the system default locale encoding. .TP \fBwraplength=\fP\fINUMBER\fP The number of characters at which to wrap each message line. The default is 65. Command line option: none .TP .B \fIcolor*\fP Color settings for the various log parts, syntax is \fIcolor\fP or \fItype\fP\fB;\fP\fIcolor\fP\&. The \fItype\fP can be \fBbold\fP, \fBlight\fP, \fBblink\fP, \fBinvert\fP\&. The \fIcolor\fP can be \fBdefault\fP, \fBblack\fP, \fBred\fP, \fBgreen\fP, \fByellow\fP, \fBblue\fP, \fBpurple\fP, \fBcyan\fP, \fBwhite\fP, \fBBlack\fP, \fBRed\fP, \fBGreen\fP, \fBYellow\fP, \fBBlue\fP, \fBPurple\fP, \fBCyan\fP or \fBWhite\fP\&. Command line option: none .TP \fBcolorparent=\fP\fISTRING\fP Set parent color. Default is \fBwhite\fP\&. .TP \fBcolorurl=\fP\fISTRING\fP Set URL color. Default is \fBdefault\fP\&. .TP \fBcolorname=\fP\fISTRING\fP Set name color. Default is \fBdefault\fP\&. .TP \fBcolorreal=\fP\fISTRING\fP Set real URL color. Default is \fBcyan\fP\&. .TP \fBcolorbase=\fP\fISTRING\fP Set base URL color. Default is \fBpurple\fP\&. .TP \fBcolorvalid=\fP\fISTRING\fP Set valid color. Default is \fBbold;green\fP\&. .TP \fBcolorinvalid=\fP\fISTRING\fP Set invalid color. Default is \fBbold;red\fP\&. .TP \fBcolorinfo=\fP\fISTRING\fP Set info color. Default is \fBdefault\fP\&. .TP \fBcolorwarning=\fP\fISTRING\fP Set warning color. Default is \fBbold;yellow\fP\&. .TP \fBcolordltime=\fP\fISTRING\fP Set download time color. Default is \fBdefault\fP\&. .TP \fBcolorreset=\fP\fISTRING\fP Set reset color. Default is \fBdefault\fP\&. .UNINDENT .SS gml .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBparts=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBencoding=\fP\fISTRING\fP See \fI\%[text]\fP section above. .UNINDENT .SS dot .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBparts=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBencoding=\fP\fISTRING\fP See \fI\%[text]\fP section above. .UNINDENT .SS csv .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBparts=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBencoding=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBseparator=\fP\fICHAR\fP Set CSV separator. Default is a semicolon (\fB;\fP). .TP \fBquotechar=\fP\fICHAR\fP Set CSV quote character. Default is a double quote (\fB\(dq\fP). .TP \fBdialect=\fP\fISTRING\fP Controls the output formatting. See \X'tty: link https://docs.python.org/3/library/csv.html#csv.Dialect'\fI\%https://docs.python.org/3/library/csv.html#csv.Dialect\fP\X'tty: link'\&. Default is \fBexcel\fP\&. .UNINDENT .SS sql .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBparts=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBencoding=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBdbname=\fP\fISTRING\fP Set database name to store into. Default is \fBlinksdb\fP\&. .TP \fBseparator=\fP\fICHAR\fP Set SQL command separator character. Default is a semicolon (\fB;\fP). .UNINDENT .SS html .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBparts=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBencoding=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBcolorbackground=\fP\fICOLOR\fP Set HTML background color. Default is \fB#fff7e5\fP\&. .TP \fBcolorurl=\fP Set HTML URL color. Default is \fB#dcd5cf\fP\&. .TP \fBcolorborder=\fP Set HTML border color. Default is \fB#000000\fP\&. .TP \fBcolorlink=\fP Set HTML link color. Default is \fB#191c83\fP\&. .TP \fBcolorwarning=\fP Set HTML warning color. Default is \fB#e0954e\fP\&. .TP \fBcolorerror=\fP Set HTML error color. Default is \fB#db4930\fP\&. .TP \fBcolorok=\fP Set HTML valid color. Default is \fB#3ba557\fP\&. .UNINDENT .SS failures .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBencoding=\fP\fISTRING\fP See \fI\%[text]\fP section above. .UNINDENT .SS xml .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBparts=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBencoding=\fP\fISTRING\fP See \fI\%[text]\fP section above. .UNINDENT .SS gxml .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBparts=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBencoding=\fP\fISTRING\fP See \fI\%[text]\fP section above. .UNINDENT .SS sitemap .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBparts=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBencoding=\fP\fISTRING\fP See \fI\%[text]\fP section above. .TP \fBpriority=\fP\fIFLOAT\fP A number between 0.0 and 1.0 determining the priority. The default priority for the first URL is 1.0, for all child URLs 0.5. .TP \fBfrequency=\fP[\fBalways\fP|\fBhourly\fP|\fBdaily\fP|\fBweekly\fP|\fBmonthly\fP|\fByearly\fP|\fBnever\fP] How frequently pages are changing. Default is \fBdaily\fP\&. .UNINDENT .SH LOGGER PARTS .INDENT 0.0 .TP \fBall\fP for all parts .TP \fBid\fP a unique ID for each logentry .TP \fBrealurl\fP the full url link .TP \fBresult\fP valid or invalid, with messages .TP \fBextern\fP 1 or 0, only in some logger types reported .TP \fBbase\fP base href=... .TP \fBname\fP name and \(dqname\(dq .TP \fBparenturl\fP if any .TP \fBinfo\fP some additional info, e.g. FTP welcome messages .TP \fBwarning\fP warnings .TP \fBdltime\fP download time .TP \fBchecktime\fP check time .TP \fBurl\fP the original url name, can be relative .TP \fBintro\fP the blurb at the beginning, \(dqstarting at ...\(dq .TP \fBoutro\fP the blurb at the end, \(dqfound x errors ...\(dq .UNINDENT .SH MULTILINE .sp Some option values can span multiple lines. Each line has to be indented for that to work. Lines starting with a hash (\fB#\fP) will be ignored, though they must still be indented. .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C ignore= lconline bookmark # a comment ^mailto: .ft P .fi .UNINDENT .UNINDENT .SH EXAMPLE .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C [output] log=html [checking] threads=5 [filtering] ignorewarnings=http\-moved\-permanent .ft P .fi .UNINDENT .UNINDENT .SH PLUGINS .sp All plugins have a separate section. If the section appears in the configuration file the plugin is enabled. Some plugins read extra options in their section. .SS AnchorCheck .sp Checks validity of HTML anchors. When checking local files, URLs with anchors that link to directories e.g. \(dqexample/#anchor\(dq are not supported. There is no such limitation when using http(s). .SS LocationInfo .sp Adds the country and if possible city name of the URL host as info. Needs GeoIP or pygeoip and a local country or city lookup DB installed. .SS RegexCheck .sp Define a regular expression which prints a warning if it matches any content of the checked link. This applies only to valid pages, so we can get their content. .INDENT 0.0 .TP \fBwarningregex=\fP\fIREGEX\fP Use this to check for pages that contain some form of error message, for example \(dqThis page has moved\(dq or \(dqOracle Application error\(dq. \fIREGEX\fP should be unquoted. .sp Note that multiple values can be combined in the regular expression, for example \(dq(This page has moved|Oracle Application error)\(dq. .UNINDENT .SS SslCertificateCheck .sp Check SSL certificate expiration date. Only internal https: links will be checked. A domain will only be checked once to avoid duplicate warnings. .INDENT 0.0 .TP \fBsslcertwarndays=\fP\fINUMBER\fP Configures the expiration warning time in days. .UNINDENT .SS HtmlSyntaxCheck .sp Check the syntax of HTML pages by submitting their URLs to the online W3C HTML validator. If a page URL is not accessible to the validator no check is performed and no warning given. See \X'tty: link https://validator.w3.org/docs/api.html'\fI\%https://validator.w3.org/docs/api.html\fP\X'tty: link'\&. .sp \fBNOTE:\fP .INDENT 0.0 .INDENT 3.5 The HtmlSyntaxCheck plugin is currently broken and is disabled. .UNINDENT .UNINDENT .SS HttpHeaderInfo .sp Print HTTP headers in URL info. .INDENT 0.0 .TP \fBprefixes=\fP\fIprefix1\fP[,*prefix2*]... List of comma separated header prefixes. For example to display all HTTP headers that start with \(dqX\-\(dq. .UNINDENT .SS CssSyntaxCheck .sp Check the syntax of CSS stylesheets by submitting their URLs to the online W3C CSS validator. If a stylesheet URL is not accessible to the validator no check is performed and no warning given. See \X'tty: link https://jigsaw.w3.org/css-validator/manual.html#expert'\fI\%https://jigsaw.w3.org/css\-validator/manual.html#expert\fP\X'tty: link'\&. .SS VirusCheck .sp Checks the page content for virus infections with clamav. A local clamav daemon must be installed. .INDENT 0.0 .TP \fBclamavconf=\fP\fIfilename\fP Filename of \fBclamd.conf\fP config file. .UNINDENT .SS PdfParser .sp Parse PDF files for URLs to check. Needs the \X'tty: link https://pypi.org/project/pdfminer.six/'\fI\%pdfminer.six\fP\X'tty: link' Python package installed. .SS WordParser .sp Parse Word files for URLs to check. Needs the \X'tty: link https://pypi.org/project/pywin32/'\fI\%pywin32\fP\X'tty: link' Python extension installed. .SS MarkdownCheck .sp Parse Markdown files for URLs to check. .INDENT 0.0 .TP \fBfilename_re=\fP\fIREGEX\fP Regular expression matching the names of Markdown files. .UNINDENT .SH WARNINGS .sp The following warnings are recognized by \fBignorewarnings\fP and \fBignorewarningsforurls\fP: .INDENT 0.0 .TP \fBfile\-anchorcheck\-directory\fP A local directory with an anchor, not supported by AnchorCheck. .TP \fBfile\-missing\-slash\fP The file: URL is missing a trailing slash. .TP \fBfile\-system\-path\fP The file: path is not the same as the system specific path. .TP \fBftp\-missing\-slash\fP The ftp: URL is missing a trailing slash. .TP \fBhttp\-cookie\-store\-error\fP An error occurred while storing a cookie. .TP \fBhttp\-empty\-content\fP The URL had no content. .TP \fBhttp\-rate\-limited\fP Too many HTTP requests. .TP \fBhttp\-redirected\fP Redirected to a different URL. .TP \fBmail\-no\-mx\-host\fP The mail MX host could not be found. .TP \fBurl\-content\-size\-zero\fP The URL content size is zero. .TP \fBurl\-content\-too\-large\fP The URL content size is too large. .TP \fBurl\-content\-type\-unparseable\fP The URL content type is not parseable. .TP \fBurl\-effective\-url\fP The effective URL is different from the original. .TP \fBurl\-error\-getting\-content\fP Could not get the content of the URL. .TP \fBurl\-obfuscated\-ip\fP The IP is obfuscated. .TP \fBurl\-whitespace\fP The URL contains leading or trailing whitespace. .UNINDENT .SH SEE ALSO .sp \fB\fI\%linkchecker(1)\fP\fP .SH AUTHOR Bastian Kleineidam .SH COPYRIGHT 2000-2016 Bastian Kleineidam, 2010-2024 LinkChecker Authors .\" Generated by docutils manpage writer. . linkchecker-10.5.0/doc/robots.txt.example000066400000000000000000000004701466565367000203520ustar00rootroot00000000000000# Simple robots.txt example, put this into your web root. # See the complete reference at # http://www.robotstxt.org/wc/norobots-rfc.html # disallow cgi-bin access for all robots User-agent: * Disallow: /cgi-bin/ # All LinkChecker versions are not allowed to check anything User-agent: LinkChecker Disallow: / linkchecker-10.5.0/doc/src/000077500000000000000000000000001466565367000154355ustar00rootroot00000000000000linkchecker-10.5.0/doc/src/Makefile000066400000000000000000000021251466565367000170750ustar00rootroot00000000000000# You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= -W --keep-going SPHINXBUILD ?= python3 -m sphinx.cmd.build SPHINXINTL ?= python3 -m sphinx_intl.commands SOURCEDIR = . BUILDDIR = _build LANGUAGE = en # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) gettext: @$(SPHINXBUILD) -b gettext "$(SOURCEDIR)" -d "$(BUILDDIR)/i18n/doctrees" ../i18n/gettext man/* $(SPHINXOPTS) $(O) html: @$(SPHINXBUILD) -b html "$(SOURCEDIR)" -d "$(BUILDDIR)/doctrees" ../html $(SPHINXOPTS) $(O) man: @$(SPHINXBUILD) -b man "$(SOURCEDIR)" -d "$(BUILDDIR)/doctrees" ../man/$(LANGUAGE) $(SPHINXOPTS) $(O) locale: gettext @$(SPHINXINTL) update -p ../i18n/gettext -l de .PHONY: help gettext html locale man Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) linkchecker-10.5.0/doc/src/_templates/000077500000000000000000000000001466565367000175725ustar00rootroot00000000000000linkchecker-10.5.0/doc/src/_templates/layout.html000066400000000000000000000005721466565367000220010ustar00rootroot00000000000000{% extends "!layout.html" %} {% block menu %} {{ super() }} {% endblock %} linkchecker-10.5.0/doc/src/code/000077500000000000000000000000001466565367000163475ustar00rootroot00000000000000linkchecker-10.5.0/doc/src/code/index.rst000066400000000000000000000112741466565367000202150ustar00rootroot00000000000000:github_url: https://github.com/linkchecker/linkchecker/blob/master/doc/src/install.rst Code ==== LinkChecker comprises the linkchecker executable and linkcheck package. .. autosummary:: :recursive: :toctree: linkcheck linkcheck .. rubric:: Running linkchecker provides the command-line arguments and reads a list of URLs from standard input, reads configuration files, drops privileges if run as root, initialises the chosen logger and collects an optional password. Uses :meth:`linkcheck.director.get_aggregate` to obtain an *aggregate* object :class:`linkcheck.director.aggregator.Aggregate` that includes :class:`linkcheck.cache.urlqueue.UrlQueue`, :class:`linkcheck.plugins.PluginManager` and :class:`linkcheck.cache.results.ResultCache` objects. Adds URLs in the form of *url_data* objects to the aggregate's *urlqueue* with :meth:`linkcheck.cmdline.aggregate_url` which uses :meth:`linkcheck.checker.get_url_from` to return a *url_data* object that is an instance of one of the :mod:`linkcheck.checker` classes derived from :class:`linkcheck.checker.urlbase.UrlBase`, according to the URL scheme. .. graphviz:: :alt: linkcheck.checker classes digraph "linkcheck.checker classes" { charset="utf-8" rankdir=BT "1" [label="DnsUrl", shape="record", href="../code/linkcheck/linkcheck.checker.dnsurl.html", target="_blank"]; "2" [label="FileUrl", shape="record", href="../code/linkcheck/linkcheck.checker.fileurl.html", target="_blank"]; "3" [label="FtpUrl", shape="record", href="../code/linkcheck/linkcheck.checker.ftpurl.html", target="_blank"]; "4" [label="HttpUrl", shape="record", href="../code/linkcheck/linkcheck.checker.httpurl.html", target="_blank"]; "5" [label="IgnoreUrl", shape="record", href="../code/linkcheck/linkcheck.checker.ignoreurl.html", target="_blank"]; "6" [label="InternPatternUrl", shape="record", href="../code/linkcheck/linkcheck.checker.internpaturl.html", target="_blank"]; "7" [label="ItmsServicesUrl", shape="record", href="../code/linkcheck/linkcheck.checker.itmsservicesurl.html", target="_blank"]; "8" [label="MailtoUrl", shape="record", href="../code/linkcheck/linkcheck.checker.mailtourl.html", target="_blank"]; "9" [label="UnknownUrl", shape="record", href="../code/linkcheck/linkcheck.checker.unknownurl.html", target="_blank"]; "10" [label="UrlBase", shape="record", href="../code/linkcheck/linkcheck.checker.urlbase.html", target="_blank"]; "1" -> "10" [arrowhead="empty", arrowtail="none"]; "2" -> "10" [arrowhead="empty", arrowtail="none"]; "3" -> "6" [arrowhead="empty", arrowtail="none"]; "4" -> "6" [arrowhead="empty", arrowtail="none"]; "5" -> "9" [arrowhead="empty", arrowtail="none"]; "6" -> "10" [arrowhead="empty", arrowtail="none"]; "7" -> "10" [arrowhead="empty", arrowtail="none"]; "8" -> "10" [arrowhead="empty", arrowtail="none"]; "9" -> "10" [arrowhead="empty", arrowtail="none"]; } Optionally initialises profiling. Starts the checking with :meth:`linkcheck.director.check_urls`, passing the *aggregate*. Finally it counts any errors and exits with the appropriate code. .. rubric:: Checking & Parsing That is: - Checking a link is valid - Parsing the document the link points to for new links :meth:`linkcheck.director.check_urls` authenticates with a login form if one is configured via :meth:`linkcheck.director.aggregator.Aggregate.visit_loginurl`, starts logging with :meth:`linkcheck.director.aggregator.Aggregate.logger.start_log_output` and calls :meth:`linkcheck.director.aggregator.Aggregate.start_threads` which instantiates a :class:`linkcheck.director.checker.Checker` object with the urlqueue if there is at least one thread configured, else it calls :meth:`linkcheck.director.checker.check_urls` which loops through the entries in the *urlqueue*. Either way :meth:`linkcheck.director.checker.check_url` tests to see if *url_data* already has a result and whether the cache already has a result for that key. If not it calls *url_data.check()*, which calls *url_data.check_content()* that runs content plugins and returns *do_parse* according to *url_data.do_check_content* and :meth:`linkcheck.checker.urlbase.UrlBase.allows_recursion` which includes :meth:`linkcheck.checker.urlbase.UrlBase.allows_simple_recursion` that is monitoring the recursion level (with :attr:`linkcheck.checker.urlbase.UrlBase.recursion_level`). If *do_parse* is True, passes the *url_data* object to :meth:`linkcheck.parser.parse_url` to call a `linkcheck.parser.parse_` method according to the document type e.g. :meth:`linkcheck.parser.parse_html` for HTML which calls :meth:`linkcheck.htmlutil.linkparse.find_links` passing *url_data.get_soup()* and *url_data.add_url*. `url_data.add_url` puts the new *url_data* object on the *urlqueue*. linkchecker-10.5.0/doc/src/code_of_conduct.rst000066400000000000000000000000471466565367000213050ustar00rootroot00000000000000.. include:: ../../CODE_OF_CONDUCT.rst linkchecker-10.5.0/doc/src/conf.py000066400000000000000000000047351466565367000167450ustar00rootroot00000000000000import os import sys sys.path.insert(0, os.path.abspath('../..')) # -- Project information ----------------------------------------------------- import linkcheck.configuration project = 'LinkChecker' copyright = linkcheck.configuration.Copyright.split("Copyright (C) ")[1] version = linkcheck.configuration.Version release = version # -- General configuration --------------------------------------------------- extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.autosectionlabel', 'sphinx.ext.autosummary', 'sphinx.ext.extlinks', 'sphinx.ext.graphviz', 'sphinx.ext.viewcode', 'sphinx_epytext', 'sphinx_rtd_theme', 'sphinx_sitemap', ] locale_dirs = ['../i18n/locales'] templates_path = ['_templates'] today_fmt = '%B %d, %Y' # -- Options for HTML output ------------------------------------------------- html_favicon = 'images/favicon.ico' html_logo = 'images/logo128x128.png' html_theme = 'sphinx_rtd_theme' html_theme_options = { 'collapse_navigation': False } # only use :manpage: within man pages manpages_url = '{page}.html' # -- Options for man output ------------------------------------------------- man_pages = [ ( 'man/linkchecker', 'linkchecker', 'Kommandozeilenprogramm zum Prüfen von HTML Dokumenten und ' 'Webseiten auf ungültige Verknüpfungen' if tags.has('de') else 'command line client to check HTML documents and websites for broken links', ['Bastian Kleineidam '], 1), ( 'man/linkcheckerrc', 'linkcheckerrc', 'Konfigurationsdatei für LinkChecker' if tags.has('de') else 'configuration file for LinkChecker', ['Bastian Kleineidam '], 5), ] # -- Extension configuration ------------------------------------------------- autoclass_content = 'both' autodoc_default_options = { 'members': True, 'undoc-members': True, 'show-inheritance': True, } autodoc_member_order = 'groupwise' autosectionlabel_prefix_document = True autosummary_mock_imports = ['ctypes', 'linkcheck.__main__'] extlinks = {'pypi': ('https://pypi.org/project/%s/', '%s')} graphviz_output_format = 'svg' # sitemap html_baseurl = 'https://linkchecker.github.io/linkchecker/' sitemap_locales = [None] sitemap_url_scheme = "{link}" # -- Mock -------------------------------------------------------------------- import linkcheck.logger linkcheck.logger.failures.FailuresLogger.LoggerArgs = { 'filename': '$XDG_DATA_HOME/linkchecker/failures'} linkchecker-10.5.0/doc/src/contributing.rst000066400000000000000000000000441466565367000206740ustar00rootroot00000000000000.. include:: ../../CONTRIBUTING.rst linkchecker-10.5.0/doc/src/faq.rst000066400000000000000000000105741466565367000167450ustar00rootroot00000000000000:github_url: https://github.com/linkchecker/linkchecker/blob/master/doc/src/faq.rst Frequently Asked Questions ========================== **Q: LinkChecker produced an error, but my web page is okay with Mozilla/IE/Opera/... Is this a bug in LinkChecker?** A: Please check your web pages first. Are they really okay? Often the major browsers are very forgiving and good at handling HTML or HTTP errors, while LinkChecker complains in most cases of invalid content. Enable the :ref:`man/linkcheckerrc:HtmlSyntaxCheck` plugin, or check if you are using a proxy which produces the error. **Q: I still get an error, but the page is definitely okay.** A: Some servers deny access to automated tools (also called robots) like LinkChecker. This is not a bug in LinkChecker but rather a policy by the webmaster running the website you are checking. Look in the ``/robots.txt`` file which follows the `robots.txt exclusion standard `_. For identification LinkChecker adds to each request a User-Agent header like this:: Mozilla/5.0 (compatible; LinkChecker/9.4; +https://linkchecker.github.io/linkchecker/) If you yourself are the webmaster, consider allowing LinkChecker to check your web pages by adding the following to your robots.txt file:: User-Agent: LinkChecker Allow: / **Q: How can I tell LinkChecker which proxy to use?** A: LinkChecker works automatically with proxies. In a Unix or Windows environment, set the http_proxy or https_proxy environment variables to a URL that identifies the proxy server before starting LinkChecker. For example: .. code-block:: console $ http_proxy="http://www.example.com:3128" $ export http_proxy **Q: The link "mailto:john@company.com?subject=Hello John" is reported as an error.** A: You have to quote special characters (e.g. spaces) in the subject field. The correct link should be "mailto:...?subject=Hello%20John" Unfortunately browsers like IE and Netscape do not enforce this. **Q: Has LinkChecker JavaScript support?** A: No, it never will. If your page is only working with JS, it is better to use a browser testing tool like `Selenium `_. **Q: Is the LinkCheckers cookie feature insecure?** A: Potentially yes. This depends on what information you specify in the cookie file. The cookie information will be sent to the specified hosts. Also, the following restrictions apply for cookies that LinkChecker receives from the hosts it check: - Cookies will only be sent back to the originating server (i.e. no third party cookies are allowed). - Cookies are only stored in memory. After LinkChecker finishes, they are lost. - The cookie feature is disabled as default. **Q: LinkChecker retrieves a /robots.txt file for every site it checks. What is that about?** A: LinkChecker follows the `robots.txt exclusion standard `_. To avoid misuse of LinkChecker, you cannot turn this feature off. See the `Web Robot pages `_ and the `Spidering report `_ for more info. If you yourself are the webmaster, consider allowing LinkChecker to check your web pages by adding the following to your robots.txt file:: User-Agent: LinkChecker Allow: / **Q: How do I print unreachable/dead documents of my website with LinkChecker?** A: No can do. This would require file system access to your web repository and access to your web server configuration. **Q: How do I check HTML/XML/CSS syntax with LinkChecker?** A: Enable the :ref:`man/linkcheckerrc:HtmlSyntaxCheck` and :ref:`man/linkcheckerrc:CssSyntaxCheck` plugins. **Q: I want to have my own logging class. How can I use it in LinkChecker?** A: A Python API lets you define new logging classes. Define your own logging class as a subclass of *_Logger* or any other logging class in the *log* module. Then call the *add_logger* function in *Config.Configuration* to register your new Logger. After this append a new Logging instance to the fileoutput. .. code-block:: python import linkcheck class MyLogger(linkcheck.logger._Logger): LoggerName = 'mylog' LoggerArgs = {'fileoutput': log_format, 'filename': 'foo.txt'} # ... cfg = linkcheck.configuration.Configuration() cfg.logger_add(MyLogger) cfg['fileoutput'].append(cfg.logger_new(MyLogger.LoggerName)) linkchecker-10.5.0/doc/src/images/000077500000000000000000000000001466565367000167025ustar00rootroot00000000000000linkchecker-10.5.0/doc/src/images/COPYING.images000066400000000000000000000227241466565367000212100ustar00rootroot00000000000000The Oxygen Icon Theme Copyright (C) 2007 Nuno Pinheiro Copyright (C) 2007 David Vignoni Copyright (C) 2007 David Miller Copyright (C) 2007 Johann Ollivier Lapeyre Copyright (C) 2007 Kenneth Wimer Copyright (C) 2007 Riccardo Iaconelli and others This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . Clarification: The GNU Lesser General Public License or LGPL is written for software libraries in the first place. We expressly want the LGPL to be valid for this artwork library too. KDE Oxygen theme icons is a special kind of software library, it is an artwork library, it's elements can be used in a Graphical User Interface, or GUI. Source code, for this library means: - where they exist, SVG; - otherwise, if applicable, the multi-layered formats xcf or psd, or otherwise png. The LGPL in some sections obliges you to make the files carry notices. With images this is in some cases impossible or hardly useful. With this library a notice is placed at a prominent place in the directory containing the elements. You may follow this practice. The exception in section 5 of the GNU Lesser General Public License covers the use of elements of this art library in a GUI. kde-artists [at] kde.org ----- GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. linkchecker-10.5.0/doc/src/images/README.images000066400000000000000000000004331466565367000210260ustar00rootroot00000000000000logo128x128.png and favicon.ico are Oxygen Icons' categories/applications-development-web. logo128x128.png simply renamed and favicon.ico converted using png2ico. Oxygen icons copyright KDE and licenced under the GNU LGPL version 3. https://develop.kde.org/frameworks/oxygen-icons/ linkchecker-10.5.0/doc/src/images/favicon.ico000066400000000000000000000070661466565367000210340ustar00rootroot00000000000000h& ( @ʅ4[Z[4 Sk?׫mkΝ\Jz?93{e*)O$yWڥIԬ%QWk4•a[H/raB˶pQėrfϏIP4߿d6I*|ClIѼdģRS4Z*b+FB>͙Ti7naZOФb;ܵ>!m/Hf+r@wT;]'YL'\;]-f|V-ȑZՠPK2G?5h=ʛ@,]1™ivT*VDMĉZsST%bBłAg3k?שtE'w<vCf6`MwP^0ɒTШh/W.o;ذoG,ȜÔgC"Q!d/@'M,R/hHg?vW^8@i;h6|ZV/X:s;zFk;W,a/ϝP4c;4 A)K/R+m5l6ČZiJ˔TC(qBE?4f8mKN+A'J0e6t;*aGd(Uq]_ip9?`~I[ Z&lb|x)/6zg"wOMche,{WC $B%4SQj2f;DKFmJQHnP.R7-0yLk>Y: 5vr3\T1=^!+' s8NEVXo@ t#u<}A?( @|9Xrc=xvvτC;6=ĔyK?}0 YXW߭Tlc)ֲw34@5+Z(qōWsRA>QJlïgE\,RI8Xkh߹},orgQJ%q{H*͔B̘Ѥs M_Τ0'O2Эl2 wSР\I`2jT0kF $*2,~gu?phd_R@"Zhhp@KLt;šc>0ʢKJIL"lUxJC/f2hK%xS%tQ1ڱI>1T(čc̔a*o^|שe[A٥Pd6WQH¡yricӨ=!ζKˡ%̕QĉDt2U&uPa4qLyriF7~e)ΛJʜƇ9{ȗoV9]-e\{v^^^T:vTm4ѩWѭL6AoB [.M7#ř}]⾆i1ݷ͚cqolT0s:Ϡq20.Y4.!b0dF@=-շz=l;$/ȎHD%a`exFΧƈMSN$ԞFR=kH}guZԫR(ǜa0G%`@Ƒ^ӟPEl7BڭjL,T-΍BĔg=†H@iq0qS O9˓HLB5lF#g4bHpfR/ ʟÐs%@(ИF\:hNײʞg1o:"HHXT[ۂ灁WI@o WW[IV3Mk;tﰹTI[<0B0f0t BBB000.I@ 3ttB0f0:ʘeiﹹB&!9t樨0y^*I@JiMBfyyay ʘ$B0fyԥܹ0๢l`4 w倡ܹB&f00#,hdit0١ဤZb<=0yfM١Y22Pc'Q]쯹q&ـ̅P~KEt؟_klssr{]A-﹥01_#D||/{N﹥01ngRFQQZP{UUL?0;((u27䱰ܹ0yxvS)҉%YW0ya;gj6}z >C5 ?faП;GGC8Ƣǝ+p8Wɇ&yOǝx8 ٞ0y;Bm\qym???linkchecker-10.5.0/doc/src/images/logo128x128.png000066400000000000000000000637721466565367000212450ustar00rootroot00000000000000PNG  IHDR>a pHYs7\7\ǤbKGDglIDATx|%Wyw~sҌQ@dEeeXv a0d,#A3sr_USfI?ֽ^/߇JʓEj!LT 0[9<pI\tЮ"#<e,Eb)U*SL-oE=ppfg*x_l>^o\gnWk&J\Zs<RI2L IGE*p 9>!vhe((>Ϟ*σqP?N𸂧z`bt}ɕ {n'1[ cFD6!_Jҩx7FP$0R];k5g&+PbVõq qY&܊k @ N !>fKH'$`y6MCU=}l?K0wܵk[Z[34564lI~\\lDžvAU{15]dqvP9Gy͵0:duO ] xԁW' H&3RkMNi_࿒ʤB辸-{uWg=ݍ+{{͖АKPՀ*Cr56zTTS cktRaw?{8}jaNE! Z37Q݊Q?`8unny7DJY\4ӶAb1` ~W}W+-mZnԎjE@p%zP+5BZ-җŘhFFDH@q`؏9uv53fB0؀GTiYFP1Yx4G MWo;=S6rޞF|{/ywwWuk ^ssZ/34:6f*Z)H8K<E#@d8!GF"zBwDTrPܔsW~&bXM<=V^oˡ22C70uSx?)P"b F .j_nZok{Yu_56\r/5|QRKMGfh")'~ϡ LLxAmIZ=&Qz+P0$2~("x=F~A=@l JhhH;n{Izk {o5ٸl9ݧj7n2 TU\`C326=#۞y?: ́eyBR&z77z獀ەڌ={?mUWkoz}}\5Bj0->Dȹ)P+hiZ֓m"v`ב ((n98#3O+D+4pctmGz"Ocxߍx.Y5P^q N}g_oy|4~!,UmC"V{F7 < 2ΏL :̀Ἅ]39k}w6ICpCI Wu/S Z6xN|{{p!izS {l}bCශsfA| |cI(6SN`x>@^S: ª17lqNKĭo1q+ةT,kTIiRȘ)9Gh2ƿ%bs7u~~#jTz ^8,`p,t ?WO0kE%,Cd+ă$ߋE fY'ٔa7ݲunh^Av>=ԫh i(j}3 J6.W}P*6y'{g#,sμ$3WB'Dބ:0B4y&! oC'&?0e:,;?7_5bfJ2. 4"qkQA>$~ qK᭗Ē4>vNat܄8 $! 8OcP $J]o—eQ~nZG[ΛnqI7/}OG{çݗ5yMe2N}`C2R ̨Մp:׸$?:Eqn` =x̒k5\:\%+"}B+)cZ \Nbg^e07Wp){ψa{beyDjK(rEa߱| Xe`Ӆ*.: o~QA 7'87z.?y./p m;?H&: =#|&u; w0҄m뻉6m_K'33!ɘ?h?b$CZ韩J͋ iP:aw<67_8~up$>H#Zwdh1G'==Lw)lɣf5Aǥ ~oH<=MUL䬓kozO:[t}ƙ&4xS\(S/dQ'B>3:v@2W@!=7!jl"T{PQ5?r堢@cnCh99勘)X (@{!C98@fkY8,n ٛ//@(%!cx@X)Bv$ ecHH %2)@Me\'l Xw幢h>r:Ƕ~c dK9!q>oInԪȬ8weY"P>GQ(T goh({ ́mhJʃ_~dUjdR(KsƋ}y$lCGqȨ€ ljJyilN`  ;Ik])$MQ3B9xǓ 4"}St82^${g:R 缠 kA"L(bql3*՝ؼTL;Pqi ;lx`oȵ_ٱ;qm#hU]ojZNk"ΰuf0cw?UShvhQUd`o.ʮB#$|MD*fVaG9=sAOI23佃#NOrY+9G91!d^*̎2@:;ĚqBgw?MK\ {*tw6`f&3+Sҹ XEWbgILc7 NZ] Ke65ؐ1ST'X=FUzUdpɜJ!q>ܽsLJ(d^_ A':1KT,}8eӺ.YMϖ FiY.wK義xs)TOP]z%(?YνRetԾ1hZW)lUlJ\`E8m՝3,n{h݆~[rC/|?d &x0}ӋǑMDZ4eۛc"?aOXf\.f@Xu84R7p yNq0Yįa떥:ty/77* 35S޿5@+%`{?x*v^N1`v<_0:Z3Rwn))_iJGfaS? xr. br"bǶ@C099cطFG5C`)SaD"t:EJS;Of`H:2NKay&¤UM .|$ޢn77hfK6v ̈vpqܫϛ[=T('=$q`5$Ŷd.gQ\׊1z[&ዢ +7`6.V␄Qő3\<<F,Kv-@l-kɜO jx"!ojj CCCؾc;6l؀ ?Aյ@6@{͙Iؘl;ǔ3 )\LY>Pїwȷ'0_NqOYµÏtl@3Ż.[iQV2"e:&=H=@ܘ ];i>S< (T 1~af%Le cs $U|*p~ 4,$ ͉OJ XjNO85%'*(?KX&aƟDŢx'F ɯ jzlXӕR͋W|]!F?G8,`jOWSR_M45 n|&Ri?QDMT;;ΞtT+UujMs[R6!'ߜڷw/mF]h~GNmюŋzߔ6˚U#i qE &Y/}餉W\ew &b+ѽ*4JR@'v oIO>6n2%7ttŠثukےxÆNvL7Ȩ? #F\shز8oόp y&ʰ)J|V Jg3jhXsɄAuAQV f8z}1\~e]N>p;sR$ƒ)bMm 퍓x`Ku+47L?JwOd"7lq>N`Bscc-/}[8EWG64P@rq+!wP}N5:ClhkX:APIe\z"v=̆ě`Zad:w^_-豗`⽻vU4BL)4imjk`xU~D&OI B)b&ɌQ\Nm+ށ'K->L87<ۙ&~;Lu#ߴ_279|۾CK?}vN`h Ck[KW$n;0́ vV.\ӎ{<yb=ɮeuν04qͫfP#v V%쮹.IJ/zO.a V,>Z.1;3C$#փ/m؏Lh)P@lVNKoݘbzl0@enrWRX !lZ _&QyJ4 G=\.aT"w15|~Le*U>}>V,w A4N&RKRzꞟ~QXݔNSt cK16[B EYԚƟXm\bQ&F(iQJ9J~DPkj]{O M )JIЎݸ?0>zͅ5aͰhψrrnM{x+dRǭjOuiPUeVw@d&^$#,]1ޓ9SaEwS~rLrW"Ud9T߾k5-9!kFɦ$;jDY5\<,ך$vkۣLR_aIm=cHɖ-R4#mhhjEjbbթEO5 eԒ[uP# [#xs@~I ?{:>w؎:mmй&vC>us.k&t|XbTu %Map*Yog#~.Z}yƆkcv.ť,F7UG0Fc  &U{ɜ+yxa~ɌLg6TEc P}jZa, rʕ֮['L ?,JB/UIO~òGL`w{1|J$ɡ+n(IU"υ8> 6XRW9DT rpKn_e鑐d2ORGh/նE׭56hQ3"RUc{`)R9],LRqHP@~BQxވ$@E;!6a] N*okSBu=H(x.AZrӪWPQ*x>ZJ3\477E52c>5WJsn0xJaTkv#̂GsBGt:gan_y*-{Ww mea4U\e$e]Hdu(W Cp}a\H ޷`}ڷ8PaXLoDĤ0j曁DQ3T(t0<\fqտK _,1ðP,rXRYCن^x+k8RFL)ܿgW]5_~9DfaDz$~1U70<2 S爵Ž՗P>`+$Zjp,L>si T=Ŋ+/vJ>,nb?H8}f0>P䫰8U0i?OyysK%G)[_%k8:6G~,ݒ^֤0AKK3ZZ[eéLGv|tÌ Lyi|ccO͉,%Bc/4 ^pim'+j(mj޾+/}e̗ X e*}!zo9XWm]L:>{|ٍBa:x=PH-BOO<.Coƙ:Z%5CZ%h[ }.'\,`# ؄9p=yrsf;L*cy7hO0G X!d!אD`4%xB3隚[6:֡Aٞn.WF?a+NgR3jYJNJ?^ډ;@ 1Kr䉝@A׀O_A +aHqEA,a`;QflKd\ R]@dH㷮?T4fx@LY}/%غ"c|P(#%; %_7=b"),?<|FU~׷\Nh*dWgk{;4-X4.``Bb,?־ʎ:V%˲,6CoB}aCBLs2a8 KN/o K%YRKޫV-ݿ^=[{{߾IM%5[$Tb ,܅kU+#@a}˳"  7wyzzYo pPdM@PAm8"x_ydjxE) 5291/TuGKQ(F?U->@,cׇ1fgfh1f(h 7T*Rbea,hP*}| +𕪳Sb9,4U%IK# ᱮzΙA5 26pf2q  Tx " ֗7747#`=OV(x[Á#b.JON`ń @(|"}M(  Tga;[w،cG;oh'KJ f?}d"1M_ 7/hr4X Ci@̲=mHqB( P%xK&01KEaeS)>+a  6D6j? - `وeے(o%7= ssRСeJ)Ξݿ_,IT0-(c8E@<0mJi CͰGѲ4%{^R8 *kqBŋ)9aH }bj=NڐK^Fpd"n4\6AiVf>%{JOHS*D7k`wgW58j%Y<֥b85wQ.k3K.)tϲs Z[[ɦp X`~:Nbx}'0dzef!b<+MHcRHaRV뚑kETߋ"ÏϞ=' |!iXvSˋpo<hdv엠"p5k&)6/@/p+Y*-,M1]<|gוkh=}E6mS ݳֿ93K$X_$Mzl1_j}J14l[:uI *peN{Yqu}KQ "F2x-%e>/HT^ 'ޗi u)IDYB >^;م МɢonPTQF/3F;Dy LVqhj)1 ^ پj9db@Ũ6mh^X 4BGlJZiܱ8`DO߉B1|u"@'0cXtBZB/gJ .dKċ/c~:Ap6˱4#e+!" ` QyG688*EgzXEtH?x|<P?2%25]768ZW'DqzI@.+I2myp[UdAd#c?=lmB> ٰ@~Q:"dliW&F. s$?Wn,<[הxMK/50_P]S`'Gq]#KXdޟo!:uRx'u,*范<yqv+Ń L KbM"Nɯ "e]c+g5 rc/r-9/M X~j&|_UvJb@ƌipŒ#TJ \o#Zh>&QOyBxh =o/O]ETeGfo3A/|L+aӚV, d c-KtVJ$i`9lY3e`8Z$[ӚVxW2blQcAg ə%rn?WS"-Yn!ISWP9j'zpvg.¿<̘*:qIk~&,{c,4O{I|PE_ W,JdAg`%TDIGM`}[.|dHyYA A7s ZYPTOP`<2Q#, *Nk6UmF6VȈw*{}^D|5MlB;rXy+2Pu3hm_Koe%Q)1=,NeĿEBE*@#SaaD/ ~F$׊e {AJ ^td?aDx>JWdZ\ȁ^O9BWVIӢ)lEȪrl-=_ǭUg!QNNMYCLAjV-4?(Hxϔ\xM^ok@_A,dXVt/Qv ˆ)z'064J_߁^+)Jb&Q+]@2'g`3^r@рT:A뛂j4⽳4 V7Jv(/3cb.Pu;\+X sGO7&tdD}FjW`>Nyeb|_gl`уm,ՄF G|?K?M+.Q=a^`OBDoAx׏%N2-AX S>B{s3Hgs0 FQ *;XBB*߰^ YO STvQ`M% [,#!9)1 ) |I)h%JR5@>p4f 9>7!LœV{/ڎycӦFgq4hY%Pa~XJ(MDWp+KTP:4u$8gpGK(47סzXKӬ;ÔO,ԙq>#@?KtkPA" Z4y}9V#@D Q3nw3-c 1l7n}`r|DH#?WF|Ӹs[=-?ֺ03݇J ]}2o2`|Yވ}pFX8/ADaQSs؅+@ &ݍf*oV JKR;?M;zZQ/DN  ) _d&i}6VX5F4e" uo9|7N?FG{ nCӇ\R3{22v3mʉn(qrgNe1ʸL'=8ՃL 2% F|jk7>jX 40=E s o?E/8zҫ)6pԲ4{{5 Ch[/0<ư 0poeglVaYQ1DO4tIcR)%;[`3 u1$R@~o1~8yR6ɞ 9ǟݍT&#)XI(:ݬ=wV~`0~{t(QEEWdp$;sll<9 Ad?G-Q(}lWV ‡ED~n'k?%윒PLC%]ҮvupI2/L}p1HʼQƱWSgGRv  $: pogy#<׊PpAn6 A%ƺXRr; B9=R˦KpMQ'ǑYSkXsCMf[9N3" QN |}G&v6%XWOazok~[GQLyb-Jut"^ZAq|qgi~!g|N8K9U]DUZ@QTGHJ>tdG ^)7KYFx=%µK )Ul/ww3džL!6UE|YZZx8R "1==;=xW㗱5L~m}h}%6H )?Fg lTm^~?XR 2BGEզssN,okm^ ,2y=0(%\N¿q~/U2PF|F7C.M'O]UᖯXUNj8U䦨*Ta_6~HcpoiƝm_@gKEڧ㄰B\:|AF]ځrܟR5`thL͡.KeIՋϏgKk0/Z4j]!Σ (zQsPr= #xd*%;vo?8 ;U^|Lx^y% Fʫ<^$TmЦϣTC1Mwb[ se^%h o Qqk8I6.؏)(B÷[7[ ԐBk{e FɊJ_nt/X_[O/{v[#EtsE ӟ4~? A N`3݌ \“]rQcrx-  a ^r2%++_Ws9R2PAV83t05j,^/{ 9'%ghFhsID!I]ǎ޺ _dHf;l+Y 9jȬ'O<[r ebN-rUO |`zok}mI\1"S Vb2 l ~+t * $*0jkY먿 E+?ݸ];T}h܊}Z?b^C:}u!pk;ﮌ_+2oF) M?DžN,8-vB7Fq((;)cWj )_ʾv#'h6+6K@ψףTa_oy̹9⺑3-[読tjHZ}q#v žka(D!.RqeKc;v{ ]&!֖S=yʲ TepBfK|qɔc\ʫGRaBJPLFy$,Lށ[c}te^x>G0:a`o3fs 94ӧ߷.]>zʠivt;=xI\,Y7vBR6Jv~*hcɄ4:>ߟ?7+$|> OgMP3e /_k{tJesNoqoˌ8/K8pxl{4,.Qz]?[Xߍ}m-\1Y?OLebXPe5)E /i|dRJ_k)iϧhF!;~'$Rn?݀5m93>[?ob*݃ 97>$;75lfI4wޢYǮn&/\֮\()j6bHbe\f- iv!_KM? e3 ߑto`ofw< H ^oFx#Z T4yj帀—R&2|5Bk(y+}~pn_Nt>@UJXq=n/TW?z|75UK雤,?Jy ׬u[3U,LöIj k7w'x7( ({RDe%7~yC/d;U-R/um9WaR}6{_""5X ^e!Z- q)Pw8`f^ibdo0a(7!%2RՊ6jܝSo>,,Vp5R"YHelM33vy]=}gXȠx҇}}4WҊ9Pے޼[^<1y|7/%z@&$I85_]V`-@}\X<ҦmB_~0'm>@%Hñq)\/`fm^D݀z;˼B#(GxYo݉,Yn# (bQlCUYkJz/CMlMI|/;t{W$Y^鏒 KIF+#kL8"|=R#X*urU׿ViJ$oqX,%pSE u٘pz _>S28QpdME,(E9Lp32$n/':gGq:TÏrʷnG^"]mm7\oX'V}/ٻg&M'͠ pSIYVNߢ9"+pɹ60gO8y+Y`o;?'.rrdPNs}֦7oxlo5>tPqIdU9r(0&/= ˆI'/ܵ AC& XFS=V/EK+-˶4KO?}yp> KgN8!rHM8UpWpQbQn>}pHwfr1N'_Ac0o/?78b^_%z>\z_~5*I YYG38 RR>N}zll%E7kȖ'Jp` 목顅t<f[|,a{C{odl 뤃0u uIy{_1!PrmKLpPO&;<?Z>lC6]V1 sXȬ2 ~c6Ύn_|ӹ-K-K:a9>,I{V0Ñ;jAnA`|~s`a2hH,}7_E4 ֣|ƹCF,oIJhؑoOI:46R!u|C9zLҥR\B֕ZH&ePuKW% crU;Muk,f&_F~J@at>*`{ݵ]M+'NOx|zv.|pR9{(=SQ5Iԉ+`QcK{>'STҤ\7[1)4GU$ڛ3RikʠN$݉sҦ=: Dx3lK(l>m 8~z,<%(@۾<کo+af/^\zU1e3yvD`#52 5m%|,P>%+:B*ֿm'XbZZ  -|ˁ>N@uSS2nsCRq> =cY,nT$=6(z-4 G*׊|S;loFC!O*9-4MM5Ok-Pd'hQeSq|YpZ4]P9-˵[nX~*+uFE 4G+Iw]!Nɾ^(_xw8 l{:x&P;^wngm#|g-I诐ెgb.0=ȹBWmp^!DBGxT(Avr'2gp5K4zݜ$WM*74`P2"K׎XNFLd>rzK|9.$(è \B{;pj12Mx-|#:>]¾(4tƏl?d;SF$o(u޲엎 W>:Ƹz$DЄyZZ}(਋4 e/8,` 7.ӫC"/ܕu?޷̼Y=3%&qE DA(b "ZF@@ME"Ѣ& q'xƞ{<򖻜~wt)+}9we.si$" -D4̛82v;w0S:O4!YKma4A+4W4^BKkM WY8`xgKǾn}ERW=\,[VwKXG7܈~߸^r6OuDL}E۟6ZĬ`|sxϟ[RNx 3p6{kz}ƍqtRFAR2onN^ݺ'V_TijyH{/3 A Y ?)fF̨>]:q66@|&"!Bp,/5lkO=W?Zُ+ '.e,zQ ZݳV5^uR࣫궮iP0:ߍvj{|F~jwƨ{fL꽏`ݤgg5s4!.TM^B _eAWLBic-^H֨^v#?\7& O 삯m O*"_~rzӖ p8` o&;~O e x5[^l5Mwڀs'rq-VQBR+@hI^,g j=x__;_ҾמVǼ O݀ʷ#g+ϿS\# Rmͻs0@TQ8ou<$񟲠A-pc,@tR7>^GZQ9<t׶Z#DVQX~%{Ù/f?G_/0=oĠhUWYu[:Kz0 vI_-P4h!= l?#;B[W'zR~査{m^x>Ogj=cĚ@c7SFg5|1 {0JmT Rf -g1jEUiJ+fv~x◻݉. f[\ ~>1s"Wϔj!7c|헯󖹾P@PäOD}tsb0ݳՂΡKL 0ף\MLoz%Ha⧙`Iwt XӪ>Z) _c'!myOW65uO(KIMkhP-@M;}JFA ~ɷm qzU:8to /N`{6vh#Vy unQ7lY>XN\x:5_QGΉ(rGvFMv7mo7D !~\BOܧې[Ok"2=853b|γ&^т0ϯ}zA%24K#rP h%;^/Ș.Ųe}5/0ɧP E*,t(?&d)ݧ)%f0xi&Osgkp7^{0jDrX'M @hV=8ŸdI|K")dĵ{jΎ[C^|sqR" rKk9nDmne+%d:[aǼ_'|IjzӿV[AWkS+u} ?#ԎݭWM#̷wJWO[n[%>B$EƄSev+-nfn-O VtT^{{jeK'ZHZwĩt46׊ *cX,r=`cq  J{fnڽdrcXHHЊrARWPq ibP7;_ ~]c04YRarQ6,ϜFPvKW ^_hIY"0KkN}[^3} {͚Ӈ%#"C+% @4Gi &89HΎM?ǒD!I&;U: YH/kӢj'v Mʚo>;BkFhCD!1tupYi_Q,\9CxvpZ]ki"}QZ+vI]ͼ^U~):':ʞiurf̯?W U W:ރ&'$$2L0FJKn~#06DG6l=.rĔk8<ї8f;uǶ%x&` ߏXߏW9/%OӇ0DŽj1DLRW+apһLvc;"7c%DC5!Q=Ԧi6n 7 䩴aa1+k,V0*STn3dS<%T35yؼ+ O];{?|0cOUȁ9Sܗ O"ji\2I!/fc5vȕ/A^mk:W/G|bߟת\u}!H~=3v[cK!m3,,=c#eZq DDzL!3>fԳmW.|i{2+B S@BwM 1 \+56~?I YWㄎNZ¶, i~4?[=#c3O],Ver(WI I7E_mKt\|7].oxTXN@>j o(Xവ88Bxb2lY(,ݴ |9/$DJ>!^` BB]oYjI2=) CxMX fk={[LE47S LYkf DU32)%ovQ,\_ o}fnGhU:99@ĝΘ Z+I)%'`d- ? 03A(RDJ`,GLcv'ߞ=qhzlʼUf"~ Dt}.I!gZw^d:[)Yd=ͥ`0m~G\1Leni)NSO٘p@7?pK IHO nN~%?D,7+fM\n](m-!z: M+iiD݁p@'Քpn9<,܋<&a ! 2bL`zc̿2|uGW@ 6Z%Oh(!FxgW8u0uhbq9܇1k)I.MAcH>,#.@#"U'N}?%$ &k3tUHj&IXf},6YTR:8ykjO+旛T 7Ҕ5cF4~^ϋ4hOЖXK'HDJGa~5Es~5E3_^Rbr^?E8pvfV pk?Ex"zTXtSoftwarex+//.NN,H/J6XS\IENDB`linkchecker-10.5.0/doc/src/images/shot1.png000066400000000000000000000274731466565367000204630ustar00rootroot00000000000000PNG  IHDRf-bKGD pHYs 7˭tIME  }} IDATx]8T)z h7jr0sl |45in7`0_~PS-]|߯ѢGhHswQ}U_z?$+ȩ3yb@<~˰e^4$ 0*8+(pJ>yb4ҳ-^o<ӸMK]60?>MG~>r};G'p\"gr?39w'ci` *ŸS44<\&>vmyw?O{n';oX6NY^Fe唇8uٽTVhQ?N>p ~l@OM~O"ΰCkJ{yTw˪2t>ݩ[B1Lw3FX>H kث֍<']ٽ}10ZH{#Rli4*b7,#bVטeo:[]a$xyh|ws ffKW}Kl,^YjmyZg|\-{uQF1|v~LXn4RϫC=>UM{ne?r5-s/v"ew ӟ.ru90.6[BeUwlȌu9㊙Ӡˆdb:W5Na^`tˮ;T{ yv+ ei+e&4 ?[Y/n(>smτ4\o0G c,GS>[z=gHg-k^BuApqxNK4 Q<ϳli4*\SƷM;}5<7?6]Lz? "rdEBU(-ז,E&9,&H}.ڜlW(g9hm֣򞻿w,TV"uUύմjV'pĥ}! s\cvaF9 Gap=r#0/0 i5cԏzvYL1~1.aC0O 8Pg-.y6>7'@V9Sg) 8wQv]ⷓrXcd8  Z /̷rrgi~B,{v $p2'KL џ4?V'ODz\š&^Ӵ+?P>.\sn"rqC{mwp̸mK]{tb+CxVΏyOݪ'zoz\-Z.d ߌpE`RWśŗM&N3F!'?ܦ"`5f _)AŗOo3׮;y˦2׵DSݟ+1>1f#f2v+62W} J5<6knaVkϥR >|EFr1>}@e]oEX.}p8=6uwe#ƣ,gWt<Ýs0P<oyϳ+?G7 ~nyώ[OEda s+sM/?oWd'r{{M?MsE:>Os6_JۥF~O\ނy^-ʾv5ܦq#\cTӲmߊ^Y}#X-{B} KwK޶uGxP6z/@ʾv>{u~n_F0}Vk=Y4sG#o 8ܾ3õWv?Bρe3g]H\w\ oR~ߋ;3Tb.YRƭjmºת~X(rVsJGV!/~Ǝ ܸx˾}0?VW|ew׮umiɀz|zSY9HNY-C}Hs]emx6>ʵ14mv4jngYkM7wȳHӽ7qZܳ L~=;~F3p`oA\bY?UH"cwִJ0lO5ixyˎ79!@M^q\ݞv5W[[v~{P׾[8qe\xU1)W=չ!Wwx: pc2r.?1~آ}arExo>[?g"∳*%}CI Y}uq;yI6`v,Ga;W M/}eU 8٤x@>Tpn=~̗tG~?Ln~]~Vi'EۘYMpk>߲-ߒUmIJ~&7ۨr(/`4Y ~ ;ECwDWQbJoy;/NGWnsNJ#3wM.Gkl.X\H-mr֦kB~,wp;]M>.<0{a*,0/+~v.3rqHQC-H_,?wީC}''/Hκg>~c5`G >sq[8\ޣac03 1~2oߝ@Gɀ3W|]b$Mu#Cb.lzs[1[ wsK%hw:xh1~_~+uc;vmQ}U_z?$+3yb@<~˰e^4$ dOYN󲝹Y߷S ,l喔dz9ZD4v#*kSI]Wl k:'"7e;eb~glZ}&W>{<b8C8^)~9{{cxC0s>=='c|o\5ͷ˃ip^|-Tmpu֠}mT1ʏ>UbuQKǤ3N(sLKK0zIB*N,|lr69 f/wS+o'nUW_S|n#.5b-sv X;p{Nؾ}Ct_ܣ #ύQnUɽ1?> S+o6ߦ.'#?Ц+b<<Ydn;TnNsEH{9}v, s5NF%|BفZԏ[>Г'CuI CkJ{yw˪2t>Y[Rc &;lفN6ARX^n?9Y5iއ@ fKs,)WqL f)e+BXtH^<_ M3zT[ҤgcWzR붨hH>պ쉇j볓uM+?eoc4?s zOF-̵ 8g.Eεq_d^ǏN<qLH~א=]dMwY`kUT6n{sv+ e7<) djkRu1^H%KX?٫?~P&[~y'rDz*o"M3\4֑Ҭjs>_NO:->~\8ORuLm7zv.`~R<tH 881N߯}e G5o'?mҿ^b;g]c?gN!?p;-(ƏONB1L!]og#4K:.|i~~If:[amyV-ͱ^zkvֶiWfuXNJAD_L]Hុ4垻ڒH>$6{)e_}]{eOQV_r}yx۬G[>=wX깯/ԭ8D0iլm?4hQa~cڶܤ99,_$萙ȸѡSvN;i@x8S~f\ĽɍnUWfd_707l?ݭzmvkG *8?N[mb<@`2Wśln0 Z? FkӅv`5fKtKAuܬO6sJ%CSݟz>p_1ՍGe67:r;Ak`wqRq|>/TZĵqqc_Z+a }+ $.6}] 1>qh{l@#=7l#L.sy=/ !wP UN!2뵊ڟ\oorlOV~>ֽ0W;9~TݾZwGmgWJ~e\p'`sدxRW#'m.oiGxP6z/@ʾv>{u~ݾڴ;P"}~=Y4x1^oަkԢ~F;^֖\%Dſn_=F}M[ʺuօe .џov'e1*ks]emx6j} ]xrZ۵bۡQ'?fGD${o 2-Yo;]o瓹߀Q/L..:.Sru!VS-2F=oK?Y[QXlP|9"'R:dsin]mg1rig]|nMO(=,ƃ׾[8qe\x##}KyE/0:9w{{xr.?1~آ}"aV{>[?罚Ȉ*%}{0dfL%ـa۱;N#}O{< 1ȹ}*{?ug 8٤x@>Tpn=~̗tG?~?Ln~]~Vi'EۘYMpk>߲-ߒUmIJ~&7ۨr(/`4Y ~ ;EC,.ϭWCiX[^΋ӑ5[侓]|ˑ4 V%Ҵz"yik`>ˁsq\8Nnms`^ {FNJ/]w)};%Ɖa>/z od<0\{z`/3 ~d<0x s?w'b2 $=IS]Pa$ş﹋$[|\V"e`;yR Χ*18Z6׿_ EՎ=v_6w4r_އ BL;<2l4 hw}brm+=<_Eo7Yq&GNxa◝ux5'`ܹ{;Ǚ 1s~$],O׽0"GT_u f?j:_A K{ߗCjxh1~z#8JI@qX69?l;X;\ۋmy˫f͵xbfKɁ>Yo++ź~!MBV 42 mnqzPu=g:p=||a%0?A&IDAT5b}\1ߦ.'^u8OdX%K[c+.tG~<K밮#Y/Rc}p ~l@OD Ցc'e; )1-tgql KQ& c<81g:辶Ia {պQd:ה/Y{F)xoDJ-ͱ^z^Ƒc01}C VcCЭ~#yI̖QoIe_վ:Kۢ"ܷ?oW'Nڲ7>_tύ'=/VggwύմGReP3Ų?`O]:HV}kpDu}Wȼf3pO\cWVq]fR¼I9_vޡ,'=ԅyv+ e7<) djkRx1^lH%KX?٫Vv[sIE-6F eƱh1n\ey|0_6}źظ[5H iV5D9/i?W~.}aU': 6e="2fՔ83O!g4R=u{@_=nr OvoW뼵^sY/n(>smτ4\o0G c,GS>įP=gHYs_-Vd[G?fKs,)W2mڡkUxV9Dnɔq#0k" i:sWf_sb_[gVxO Sպksk[}msڸ&Jw Y}{߱s__P[qaV=7WӲ7Yy,BE߱1{a:{kvLU/\Z8n̶SPrq9P3au#0Oݴ1w=N!C䰡T _<}\8<_Q=J=/ \oYZkkcPޭݳo!}1>SA'㏺^~?xqhr0- >m?4h{1ԯϫ˾v:W|\qC{mwp̸mK]{t﫮Ⱦrstao*1[b _+7?kt?f-H#f2vUrWk`wqRq|>ş_:D60n Au%vd:;EXN&8CO:F5-{n-]=ϾzB{Xv./-yz~nm^}-}2◿ۮm_=\>?X/Ƌbcw8юe+֕v#+ަg3c@.ju!irYkqznK}oq%w[W;t?[q^)}V6YcakU?ܸ6g6YX_k1FC^_e[}'Y͝~80?aF{G[W-E~.˵z[c|1T!CGw~% n쭪"x)/;XDJs4B5 }afaxitLs8x<}w>*oTpn=~̗=i2y~n瑭]XlOn{1|e[%?6LnQQz'͕_n7sߏ'Yi@w-)Y\ڟ[;XSC鐱q#k+9}'&{# ki6XK.i D6W9k5D!?|;fqН.}߁ { Ͻ0ϗ?ry;T~$(! qb|$/^tԡS>{ wJ|$Tg3u_0أɄy` 8D-.?1^gȄy`?N dHz+>.~1恡Hs? sILݭEʏzۭ;vs9K_?i~b['?/ݭgSצuWܳz*sc jI?w_;6-"k-.NNƬH~F/.ϥW6MAAiW?/Ϫ1zàfվ6uڨnTwnS7RաMjb߈ax9NSS]vQ#z>|kS_k6ydU xAb6e;4p>wY0,uѾ O v8bFv T8IJvLm#Nݦ=AM6WK)^|Jtz8kD)\kb3YvZa ;Vȃy gⓞS1tszʳ6=_I{i+?k6]PK* 4_A$xJFP:9;HL4M~Qvsu}k&^=J 쐿!| G(Q@> | G(@WL;r3|>vE>JDRNZz@> G~Ԗ䣟V͵5}sud@TvG6M5ԭiakB'ηvsHKӌ/Gȕ|0nAL;wŐ,[עu2XZ;ܺ.$~,RK/L \lOڴ`([ _֦ {4&.5p.؊Hyizi&36OpѭZ=a5?TM(:] OTf#CN׉V=6#?pS\#"RxgLQH-Á6'ͳߤHDS>}O쇜G΄喃;>i8}>2҆N%RșWfOx0t9М,AN՗Z_^@ '[Jw &nlgVR<9|)[un+n?4sbi ٞLgRh}2KIs+\*eʚڦdZ-XZ!"K"RVM:`+qMD'eai%tx45ؚsa):"J^ Hxif'W#R&~ 6"t6fڝE7@݀Psy XkẇonR׫j^C#omN=[8@>=4{8;<걘60R1?'2G~-],Gҷ%yMM5 ?|p#Zgz9o%"~//7UCTNdô bp'"~(OW+ `-bZVOA3GD`ԼY]Z Htn1=5D~K]_VCznN>3PgT]O s8ܶ*[T!.Jz襟=g@2?\,#(yjn65$gqiDDބ;ȒJ#֦5?(Nt>4v!%?I/4&%/eY6pwSY.G|? qmc~T{ {o B]Y0DUz[glWx֭)[z.v+{.+ޯB?G$@DEE+21tr#b<.|IUU@D[J$-ELv8wEDyg+~b4HZ^9L kҚTNPG)& BBV lAۍGg/\a\ |6a9|!o5[nb?O}SQǃEg?casvk(dWtZJDWEjTaJD17e%Lx{2F쇽o&j=7kx-TH6C_b`!~fՑWIwFDSɉ@>pqVSqtD5j,Ym 9úENx*{h[u; \χg5 w>މݲ;rL>׸I<`3!_U}=Oo ܎};"Q@> GOMkٞ}GX6/u]`וQ_. vaR'[^䣝eKٵ/-j 5ŗT+p+Bs\x/X|7:ʘ\!?Gj~,j-5gQ`x齒D/3M_V y 5y7r+Qz/ڏ\w,~ FOBՌͱA c߆ "{=RJx M%ύiJYwP4SK=fD'[OBc[ݟj[x!.%9yzlLu^vpcSoʛ=<&w0qW? N~^f]jcfW }Eki15GneŷDTVz>RMT{1vs[;}(Q~)zX&GoRdId_khpW"{X,܏s^] ¢ʾcB%llj[sSu[&Ro$.G7 |'P8xR9[n"C*?;(&b@% XKܰ2bMՇlw[|&ŏȫ1g輐-@Dه!Ў7Jn pn,d,&7m 2emab/ D$'f6_Q>J΅Jݛs&JܨϼLKWwMcv^¸yWH5m#L{p;:ė"s'=fȿj0k nvUH@^( G(Q@> | ݊:3[òsϷ?wO);{0ֺ?oZZu,4,|4 |ߠz#P׾ԗ Ç={ؾꛄ{l_7\ v^=btc[YDžOoMc߯V"*>ύ$ZFzi;etP_F G?%CI^焣m/_|vSRz HVWjӂ⫬k>@' _=V9;ְRs\x/Xj<.JWDmoI;^]9Ӽ,3jjX.20Oe2]2ݹBlWSq9e܊*q`}sOdX'ק[G]=ykN̊9HU6a yŴ;d?ТBTM1V3xw͑e{06\)+?Ō9bv=Qsw5""]=+Xnn;#Zqo<+QY4ӉCCDcf'SZ/Ǟg\>T_ͷMpC|>Gzr!Wh韴GCx<`My&&k{T`R15|]ʕj˘5{/ַ9 T%N_}</W2sb߆ "JJ+#$u&պZ+Sar]B/c!{0Gn疙S!~.ɵiBrE k cJE,|T "e9cpvi&D²+~>)x^k(3yIdNW~zIuϪ$DNYv CRv|cԚU^v~4~<\NgkOw?WgTFW4]ώ\vt}9XR D$V3&I]KT`FRCe㷪͹JDg^\|[X~^1t2ZqD *vBK뀕y1RO,&-X9%VvW?9l}kvDCyiNzޑ`/t'ODoEM^SHStZ۴af15p3CDni,r:] ZDˮE7f"r LSK;C]^([yJ?^͇eZs4Sخ7gN-Kos1;9ˆx1˫>$jr؞_(\ocT@Vo3S+ joh>0r/iCrMތɒԐq/{52 uf.%21Mgܣb([[ 3 ُϩ{yFp$yJ;b>-Blڰn}w$ȩAe+ƄεVxh(pY}#Bm,&R#D)6A5j]T~7LI g["XcfFQjmvƔ4Ff.""$>̞;)z sD,9Sg;/ؘ&S"ck~S?:&^~->kX.Qo "8{賌)u/o3ui+O|S)1Kh UU TR^lMхZ`+leT]^AB*P8enS'bO!IR3Wi+t}V}U*uGwF" ܞGv@w-@Dه!6|]Nx.0v:}S \C"LL(Dǖfڰ@D_dHZLsC ُa D`,9"r07meSM^.Q׳yylɺ0/YK"Jެ?gRoJD$=J صC0^HOmu K~$[iwwТ\|7V5` /D} Ll]җwI⛘)x)9RPT|ʺ%t_$xHݛsӬ~n᝛\S]Ao_'-pYnO`?Q,1}M÷n@khbb?{OV ~n]VfC U0w/iuK6mێ腹HhB1QӖ0>G"7y%fv>jK3{_ruo)=o8}ݮVŸ梕5#ĕ)m]暿%Fc#QԵפǠ_7%9><0wr{(>fsN/XVб9}Z#\XDk`Hz>~ڝ  -#fi/B zw_vcLmt~n%m_/*$Q@> | G᭜}|Sꢐ?J.M X+V6(vL{06\""(;cNςT`=s0.ذ+ccZ5=;N'~&[,*1Vϛ}b:vC T~J37x;cJmZ0V|rv'>5u!=\#"J=ٯS8^*/Ijvtv!ftrscN dk[hz9jO>Gdj$NɎ9"ْk.{_&}Jgu8T"А~%]-Dp0EILᦒ>&*8I-ڵ@8hd"ewM-xm-hJB3hvI=>"gܣb(Yd59z3z&K=e6D&f3n/[gYKDj>sAr)HeLf uiúueߑg;+ծ?Qk /D$?\Hu/%G$9.MhSrH'T`5ZtMGwUdΥx5;Le gU\Z'S,eתm0[\+Y᫿y ⹳1E@ck})+ eó4]tZnj2xk֭)[񦡻+ ݝ `1Zӌ?c5 e J-]g]iI6]E;BRg%mtRVdۀK@&^5,w0&sFtJLDݦ-(g ũ%47ʗf"R WYT+4U^fibL$ַ d5r ]]A5*NZQeJơ,Uk5=,~S~X]3\߮0-+b"*Y&|Trs<%&]#'wv!j PKJCV0( ;ú5E~=^jpt'|vP-WgDƒԫeC*s{sU IDATgoNlxƏLW(Iin.A9h}2}Y/rDa%nʦ.0\2"ؒuag_ W,%o֟i 37%"RM &II9' Rd^ ?TL) mWTͽ*QIzADI_|}8}ǝp;&"-a&.eW#|plz@&bM JNSG8w%;'vj:D7lqoxT2%oEn[Ve+{]'( T>읛\|gD|НfCX '?19:IH+#] P|3?Y=]s*0k^€c|H#'[ڴW3wxuӍ|=:txҪ=+SySyw'`l|!sbw-9w$|tWܵ1jQhDŽ Q@> | GGVO76[K3|~+>ݱMGOիoN1}ؓk_I2Wsˍ!z>5|&vG oewKCI.ogܥXݟ(x1b?N5W~(JF)r2 G?ɐv"pɘ}Q48Y*? l -狪rGykLx߳zԜV~ Q1_C},gf%%2cmXVgc2WM[~xГbxND\@}|&JT^leJas!Z\={XgBRqw~9lg685gN?+Fju[1^WeMoV^_ Vr>hHF[8̝T/,|"6BްRk*TZPךGE);szc""rQ{Hd40{ws/7A͍iJ~󥻥W6h|jM7;:՞M{JVW͹MU*^>χI"곲)=kǦ)*2F~{fڸkcdF}7ʕM3I  3ݮT]aVV|LDegC!eLDk}Õ0^kZrkCZVVʪΞٵMWe3uTV7D&K'X/yz8|*YL: IߏVceiS!֙XReWuGYBߖW18Y,kP룜߂)lb{+[V^ IL҇RJ WYyy1k% XKܰxS!~Nw|eϵ>|{?<-2埧GɰA[UC惡ʉ,E &|3GT>f|jM1 {%eyf/4s\wn7"Y/U?.5KhiNsۖ@UXsh9GݕƏqQQ'ž3"sԦB4G|ᘿǫ^qgpW01aSlʮ<|iЃ G(Q@> =ϝG( @> _ !11O_& rMvΎ&wihL%^^~5SXT; ˶{M.؝AѤ.T+88@č&dJD5Vx!{hq=:Kϵm4k#x(nX;?) W)/2hRxvz7mK'6Vf~Yt>堽_:vC[]{:+T"?ȤUoglu]2)e֣r/8Gr_=D”#AKUנG<(bLDD_Ew"7HD>ioE*N:YOtn*+$vбz=L @㡸a5SY12`\m}|1K.([qBl%ik%cE~+ Nnc"&uZOJ+5rQ|)UO CDײwRFe1RZLqW2ŌJ}z7֭)';qUX56=㸞Z-Mnfr׷fS-vB_n! ѤfF.Kk /;)Բ.mo(4UIh.'5""ZSɘ:2˒c<ɍaI-]Kr!pS.%C &f.mYwWL}k)]"^DC {40fv᠕\N{N fb=Kzk#P;u҆ՈNyDתAe5􆢃NTXRxuԕ2;)Oۤjq1yDHLJTZd|SeG*Q%Vrv!S^R(:}nl.uUr۳r|gW圽րE܅DErwȳlavlWsQ]Mo4_r-[{Y!O\ &2szq*+ЯJ|#.y33ht}L:ll4q;KeswCL)%ڛ;]|ɒ~wѐbq#gcsdҩ,3or8|WI/;^1 w1לDES2Y2*1՗J\e1kP"N՛\MCu,uZ^e^ ?6|zxs{fJDB|\"SnSk]RKk6ym׉7FXwZnnڶgmZ+E/4׭)[ơk<7]7]h\G>jTTH^]9"/(^$QlDdwTHYck6Quz6Ѳ5R [׺8mp2ټ(,y妫Zgc/CDN'?:uMSQtrTe?7wG~&_Jٮ֣G;0b<EQs ;syu-bMKbNiW~nX w7(u*:V(dkʭH3 Hޑ umnr#jUxϢc,yYRV ?j"W#lJĥbQkw\ A'@:>ڢ /な7%랥ڵ]z7z5D~K=2tQk MwO톇;?SMc xD3[gؐri6uT_~cdYvw5'4/ Ȫ\>!"L}%hSOe%66պ1\^}Eљ6ctvfrZj;ϭ%2yG-4D[t*&Պdș7%u]k_xzD$SxlOW1Y/[n~ZTMIJw,uT #MzIrɄ."5J=dJRQ^Ldgw)"vɢX(sw$Ԅk3[j-h|z6pj`h(M^,Mmo:ݶs&+E/4֭)[桻Ʒ Q|DŽV2^>ZY'z’~Wkz8[l,sZz[N3$3OF,5dftWnO{o!qܽ7ci0qɵwV^Cz^\(DTVd4s+c鼜֣Ӑ}˄9wpuZ+ƛHt6XęR.^c63&#C OY+(/W>I%'CQd`U/2^ԽrZd:F޸LLТȲ3/rj/ǚM ijRSlN4@:<$/)[qLg mɛ7]wv~s0RltQaݚ" Mm5]w'@]܀E|wY|-GE@Jauf]L8] Rj&8ɈT Ṳ́VqWcT"=δ~vd 7qOʽSP,L&.$\ӯJ#ӭolI\=H)9{rt2%{?vݐMѭX&- 9cNT`%ģMADHy]LsY 0za+ Ғߵj#P;ۍ@jǓqE%"EV*rϢdp g!\q,ӿ˕QgV69WDQm׉Hh[!݁:%o&m`~Mh9aYpԱp?S(7*Yq+:,;[E[yf!b{Lle1f2bnȦV}Ťx*mqhGQA5~ّTd/{7w>cgYǦH.S'lu,i M˦ܑvj#SŢJKl܎es?FSRCOo ܎}G( @>lv]r檃s3̶zADe)>vQ2ۮ^q|pU-Ҳ2V=?i x65v[j\@>U\ zxrZK쑴/Wž[̺VH;?4WWglN[̦_Heij0--feskiJl5koaXU-"dVgTb6B>[N+pb"U䣟ZaKeY|* :f0դ$_=g =7,2of\fmZNf%:u غnbOVL4QE=,V6dx> G?8U"sK[ae* ѴRYMyc!fb/EߪD$Ul{;zaCɑ^.Q{ܼ\ZuvT6-m' NÜD|Ŭ{5&>'{oYJ1:\B%ӷo11 /9,urR+o1xE!f0Y~תxkSZCv=fU [H~= G(cGB|=|Q@> | G(Q@> | G(Q@> | G(Q@> _3ӎ"%A/'%U)|.x' ޯ|CmY/g |t~Tw ݦRCz6;,4,lA~9jGGʊل層wջRUC>:.IBnT0bܡvlK3LVL'^%i)JmZ -|څpƄم&w \[2'c#Jr;=MMȕʊإnZwhM ( 0ו_{Ѱ\*:&?;xBySj#CN׉V-6A%?^KֿR|}G΄d^BvȠK{v(::LDTVBg|C#grl>4ءLsDޕ/11#54XIDE9'qӳߤHDS>}OYbumX*{B:CkE,ËRc?{BsrSe+S}uL{\hڪ;Zd=khhvf1\Y!ۓLjWeҗ43aVT6;?5Mɴ]2_f+>4^}b5RD$^=̜WRC\0(lCSiwz'3Oe1F\e&׮ VQRLeBv0ҕ&xNGrPm㊵ c=&p.=|5]?*x6uh R:vGsO3IܿͿ\SU) [O:Zd=kkG5{8E9<걘608K1?'ڔߑe4 {Yz>y=≈ "٧V"r2;S6VoNTeZcjRھ3 7t>8ȑ_ݰa$u6Ymxo5GD`|S9ܒ(%a l?>.nD˸]WOc멙;aEY{+}’𶬪i,RSV&'j,}FJvϬ*n2[X"R1Ɵ8kbuJ&إpK4a9ϖ9zuI ¨ĭ:YؽD,KRk9c؅J$-;tdU޽! IDATFdblosB(/Rw/3$xP/]oh*aܐXp d1bN10[Agk}tUR2[7$`Taxї*y\xg; S0㿜LzJ:lԆa{Lm(+]&x̯ y؟ap/sTVOqAv[B爤HE&fuNxW҅/ Q^U D%DRlHn9?iH8` /?M},}ߖ}] "i1l wCN}-f͠Esw\0 V־l?ɝv> +*M "KQqbvQF[_=;Pj;K|z|au~gtE&Ú&]\j+{|!~xyo3p?"zk>asvk(dWtHDWEj;RΑլK0;/NM\;;o.vѩޱ…'C ]&Д`g³hܓ1#d?~3aܨZ!=̇Ojo _j* ~l;+1^:ikUqR㝮x`6AN{l%ejfw+*>n&-}06ܳwȽ&`SDžr{A`0? (|<C( vL̏Q@> |jJ Dz̬ܴ nMmIp]Y0>dS[1aoQ_uxK6u -6."Yߊ={^HuS)m} |ynOoK5kGHϮ}ieLLӚ359gݚPRgm#*ΏąBaUEG\WwCIɥMIt̏sяw8~pAQ 8bKN/|!QIӲ.y8J|4Xđ~yk1_C},gf%%2c5L©ʹ=3!;(OS2]2r!WԎNDA>[eb#"MmO=sqaΘ_I)Zپ~[^ {C\딧X07uU].Ũ,Tԛ?Vɦiڲ~}Ԝecu&m9bbzYHv}gu zC̊9A{ňY፮tG)כZbc-o" GJf|>rn7}!ZaS/?OoV^_ X4MF=i>X=aݷ$-suboMb-C64R"UzM0ޑaJJTͤOBmˆPIyrIdwXrk}O͗f\YI'#/"*[i=ҮM͡ طBvaSaN{>;ZG);}ݟj[x!.%9yzlLu^vpcSoJ׳mr'ClfSSS=L|gzHഽH?Jk۵ 3ݮŴk`vQ]v5X端\7cg$5ky4"F) coBr}|oXRc4[T!zxHmygBz Bv v W-\ 4M .MWXMm\ЍDPRᖦ+#%YP: #la+$`!s4Iv/dwyf>d8uk"!wVʡ-c6RWt'ٱinƉb^7L.Ym[1EǖfN%q`o}ߓe<,D6{ '8yʛ :k"HO6ޠ3T{dEi ^RH|#- z }m4}5}lpUCD@m~QZ^{GX{7Y3[{1{Fշ4vVZ?U6X<)_g$.xK0!*”3bItԒ}S$q8e_ G_d]($j ҭᑉ9H^MpYSx2 lHK>BӔD&peQ%?rS]Cy)f6~a23[ 7݋ȒBj1y-c'5•G)mrǙzP9"Ju {N~M$]]^#b0ц bбx2dn(22W-DB8z˗N}ٲ\Ez`` a2}m{vk59M]w5Mxy,;T9 CLf7h k_oч_YꍇKT͉U|МaҝLf].57s[X[dŔY di6l]d*L*It:"է{<ǛLc8,}Sl_ X)a}Qģx( @<;lģ?}>IJ?v?v;d,[J˯9H ^vv8љ6z(Ŗ^a͚b=Z5CTŵ%ak꣬eg. FZMިmJofּ(/?iN~"H-Fܫ-"N꣜>'^-fw=mo[)$>`/(g.Xxcpt-@ysCK̝j‑0rmbm م"anE\3h~?k$'J6D}_y)go&-՗d;fovN HKfJwc#b ԺYݎ{ū/DTzy[&8s"e=$F5-4VS)+;-l.[ym͇:n8`nGO9:e#"h}/Jѓ.`t o!~`=dkqkO7v@LZuUKDJoj5^ۈs_pģ^fT&+bϞnFy"Joml:S!ΞW.\TZ"5(ʜy&ocI\wT^ nWsA<jJS3bǒOD,d")+9ˈc{lB.M$ugV H-ygyc2Ҿ+ג;n*m-S(̇ZR~LXP9FQHMWsՔ?@~~NOn7W,U_~{/2 ^Sģ`͚wKjbO9:?!U"˲뀙Sk }&qSa"uG1fNx@w@a_1?nW&+%ϱҝe7x)QNuδz6a;͏'/ݞ,VKQ3;'^])ٿ0}&ZڧQ6}]2Re3]L. 1njT)u?JGm5ܔG"U+{dEr&j͑ǑcȲ#ǵ}*ӆ9壊 | {ڋrF"B( dz^՞P&Vii}.z'CM:9X #-яZXSLsNr(봧 mNAPϺv+`OXS7;amNZ?To`:+m> \Q/J@jm` + k`Ah qv1J8f(<_ _ՠ%R|r3N= >K{Nݙ!{ >Nk3TV_,L)SK7!dgmSQ1T{Zl%嗂;h#_v 27nH̠C' n{*PS 2J3#q]fA|(k^z8dxCITago5wZoD1Gtbdk̉h~HD詫G!dB(gVjlQGY%VGzPr "rOf%,GDn?pANFVT3Ѽ.cKU17ŗK?jC[m{|:i=,,&;N@;|xz9Ou c_6?M_L[DW[%χ:q9<0cOԦƌrSb}Jsj%<ɳnv4Iƫ)r=000n:/ڗ!vlVZx\2cKL=̶YpNqOR'>}Y ~7F֕,|0t2?Ο7Z|> 8gSt ģG(Q@< x~H-ol#zyS<.Ŷ6}ec +9pbbr鷵qN8z,G6mYJ]x_גxK\˴λoBpWd: TRgOxݜJ=T}.ˮf"O RSsDOEHw5g2eԡ[1?nWߒ`i٘F̦>gjdLDSYm0t)J6yqHdLz;tYnVIvBL㉁X] ڇ{mܬan5z̭GX2w9@}YJτHuO|;[2EFTRg|=ReyLaیGdцȾ%Iɴ',qwY`g51㙦 "UjnԚNT>Rp:OcH-ٖ:ii6ZLְMߨuZO~*Ӎ>5nmԿ4b➔Tҙϥy:sTLL|)=פҜݦWP~%9}}NDZ?ʟLJmA(:jɾ)QQ8& 0س:YEzJkSWB=KЌDe?*ʍ*=(9L ].^ͯ fe"aG?Ո8z'YHv;4h[}mrZt0Mg꣬to&wg DDM"odlTn4jHJ̴ PέB ?f:ǽJUi'z81Hb mhkvT;"%ȓD,UɅ9q\[ko E\a* /cr#guUAn7(Og0 jU?dUေyh.x.F-S3HS Mob'?C]g}4 \%OԿ^W쥻OuN'QSj{=ҥߨz&=}sW?Xs'Es!_#Lsf}:IM{|շQ~R')wo|2i)-;>I8g2#(|8tǼ@@Q@< x ģGV-w|\Ow;?R?UL)Yt 2JxT%p;{}rKU sM"OKg:e7TȮn)eVKą*KϲvomKjy_3y_4 }jdmmEwsg)Ho`_i> IDAT"_ڞc׽T3lFv*wlc?X΅Xg3IټxԱU v >OSOlkˀ K,9jƑdbwՠ<0xN!Cw2XX 5V=Ueߔ_I%E3Qh@< %{WJVIpyʛ#9:ʙN]wNvšdDD!1`nyb޾ˍh#~4å3lr2R Ub8&PscMh_<N$ &kQ"EÑjb+SdI.!{[B?۟5I$M{YP^1M*QE2Zko;ɫq?kԜdī"ɿ%LmL52-m[Ȉ%"QI2kzFT^2_4/e kwـqS'Ʌ9q\[/Ղ1y͎"x#!x4V:o(7!w4w]Mz?bݳl輾h_رYiqmX\%+$x7`d-u\ q;LOɞۢތq+ؒ=QW B( @< G>O#A>`}Qģ@xWKuU|NjEz='DXsĮ4bW~)͛M*?{ZUj~VrF?=HP#TKdh&4{ºVH`7Mv~_$GV3&y;^J<:Zº\`x`-f3EĎrܬ[Xj=n%xmARͨvE|:#7}^3'"IWV/8%"feQzl~ͨJZH7 Kd`U£vܦ~HyәFX*{5fu9s F~V"ڜZ^u;oo~%#/+jJ+9IlҏT ,X7]+yDYgBf dg*YL#Yt+JDkXڿ?i"" ϨES@^VU4e'P9r=z,ښ ]˫*OއZ}tS3qkafb8t/+N] O; >ec}|!l۪\+~QģxcdGYţUxQģx( @< GQģx( @< GQģx( @< GQwf$Yt=g}Y(r'ϒw3^O ( ģ;H{6CO~<|ۥ G_K꿵~7jۆ`:kހ-;Llxv_Kr ±yDٹ3:;_\B zֹ?W=WQc}nk17?<d_?Ə3NM4Ko94 <5"}!_z-e0qb 㟿}!hBD?{^$hBs͚4Ԫ^fOƎG$)*lvR|9VZբ[Uiv6u49nӠmEh%.*.8AAh~i64HDjHeIbm䩹fbV>u0gA99}sKƲfk^%ڨoaf gr('u5wԵ[AhxKsz-kp(~nRtg Ⳝp#" ݻ*.yN;(GD{@~<߻&cjr1Z| "tT}$66gO~yӸi݉X!!K[ϩuޤ}rk-^ e]>x's޽_hulK沷s"JY\6Kb3m-UO!Z )7M&ZXRHy*F=\ȩB|y.u͝Fpldb"̜Z[yTg;󻟉(}6Ho)p!xX\nɭq91Ns`b]2ѯ^3䕟מOpY"DsWUR#R;}kR.U/gY^hJ?giy\u=Zʉ]ej's!.852Pf6gm7dq'Ƀ6u֓r撿ꔪFLLO7[&m~I.J1!Hp枚oUBq..ĝ=٧7o{zVoiQ4D͆0ׅK/SN.ҜD$rܓ:󰚿 V~TmT1&Oח;-QF"eU)|ϚLs:u+|<|_9ji&(xQaUd'nsF~yhމ()z?; ݌5/Mnּ7i}ڈhv8ʕv0mSWxfFtd hP"ы>@x[DRet;OD^AVoK3j W0zzĐT.=&Eݎ*LW9^ Dď 6y.xU4}Uށ4Ri&"~4 ĉ1cB@zLhդ)nU15'VW Q ¥t|֖3U|X,%5ni5423K1T .gYEq{f~NytvBu5p!< L䩹fbB;,p#x^z*vM>;MlxV(7s[3:Z7HkE9fR4ڡeVןJׯV?3XF U =.ƧXzLg L絺&7ӜNjHUnm?x"JdG7w)X_FTI Md|1TB-oS7ˎ7`ZJ c0 }PCx*xId<*9;s}rr *d2Ub*TZnȤoDC\钽>OqWgW\iI[UT/"1빩R1ϿTQ+1߷\tsfͻu+["r$dgT'o#3tvRۼu(o<5CFDfILgKՈ;;e:~!"^vfmӟNͅjf/⺚7 P+!9yTf97jv5Q0$n)yoҼt-^Gl:{˳g͞x>|S|")_-;joz2DUm ͌J$-ǹ` 2k "4irg'eުQEoQQhb%k?Mg2I+qB8`.˥l#~ 9-?D$-EmQ"RK .+tIܧ&-yvRTB%*<[oBزDoF*a fڐۊϟШ\s-5,N Eh&2ŒY"Z}8ÎHD|t@oX_{_^?DT2N{j&'ȂDD|`["LD]3:u$p "bGU17yNw]Z0>ma1Qr$)񣧟W輷"?Q;ϤMSynSO[yG&ęh%-_䌨OgMZRm0 R/ι%av؛O5;\T[7-DlvOv_y7ⴚYϰi\fP%l_Jz9w[=w/%n<5L_C59񓯭i+b~zȕfug牚 ܍$. V὘ߜ7wQ@4aչg'0}5]/SR].;s7>[a{藮9h˅¹9C&w^{]_"iMЃ=XBw~*:u;Mwݻ-wx_V0uܲ4-8y޽p?4.Jk/atv&j>Oa}v\AB< G'<wEG( @< G?#{ uȺ隉Guvo.8IJvo|RhdmӹNEw>hfXnQ!:"=lN4~69j߃Fk=NgZF0`d}OLKf6l{3Z#;0=-nc>lu1@~V4Ϳjj&ֽ/+m7"b:sojщ;z[o蔲 G#ѢߒuX//)7zu6s/F-{9/^BtP6p:lbyřaEE!Go㡇e}!q+7pg"G%>{Mt^Ɯ.k5sgSrFYV Om_rF.yR߸COsߖ0rB[pkͻݹE,QORFmȏ2wݑj*o jZCR C~{R@tJ.!f,(K#Q0oJ*YO9:e#".nav44{\Rx$ΗV?y~ڱ [Tp66熺w̠̽|Sy5'R}Y?Km޹P2b;Yom5o75B,Gez&nIt)LW;%w=]OsM"OKUh3U~gmcәO^?y|$F;{Vjy738i- Sb^KTq%ݍM\;̟gic94boGw IDATŰ*ΰ sw} 9~#}!KRk|=ш?rb$͛fbo{귑gHVRebҦ@t "'"R{Qxg|HDZ*uI[(SFQ/:n\N3 yI%v%"n"Еhv03GRoQ.U|&CuѠ;풖2zSۣ=aLG{[d ѫMZ3CIA|g;>poM-I66E>]Xv{mglT}8Q@" ݲ x6iq6|'2k4E,9ߏnܳ J/"PjEַkzcb&svϩdl?2DbDA*{}m/êŌVpӽS .xpe;dl?Ǯ= }몆_zm UbZϮ#g=|( :4HwC)qؽnM.$Cښ|S5tP(J mdy>/Yေgz5khRw*-9'XP_=w2 =}Yy_V޿S.pDxϼRSR3|WwoԶ }7y3gk~ojD{u%Q_߿SiS}|5E:ģy,ҵ0Ej2/]3w֪F6C DDrqyBf7`d~؆#YRhsj{ l̠.n@IaOÉ2m.ÉFR'L~3F/%"wR "";b/n!j7/dFzuW_"gZ̉yTl$VS)+;-T:JƷLS6"rWsO;GlV`c-0bmF t*̝0E0v^-O|t}h1?ODS>T"Mg;ٳaEKk\`PQt "̙gB=6uGPߨvz=3p^J?U=#̨)LDʒL&J?)8P&KJM]xfUPےg|9~87&s!y- &>L*tiZ^׌埡{6DzGl;$:wxRu~oִ[/USqr}ǘDY]DdX#\3 ;0sJ=L>mq,%ϱҝe7x)QNuδz6a;͏'/ݞ,VKQ3;'^])ٿ0}&Zڧ6}]2Re3]L.z6ׁ_ q|ZH}oŰG꡽x!o$/dIj8 ֫2HKsx?׵8I-DJ5u4m0$xN{Pd4h;[vϺo5uDMbfBIeI^ZBtj{zc ls'iOi;3dڱPyG[}9^0P-eKLkc2 *Oe׼AchS3cBլNTH\ڦLocQJ/e_Kw`'3F~k0.URW$MTago5wZoD1Gtbdk̉h~HD詫G!@dB(gV7HTP[6(IKx҃4o{47+g9"r v60R -ٌeum9nYKr7o8z'YHLdī"ɿ%L[*.)$vX+2D-#!\Y>x4{7rݫvM.$CZ]"u7 cq Yn4C0k$KovҭFtvyB!q pUs*06o;n+T#qS|D=o޶ǧbR{Khb:d Çךt_02V{*eŴO~*?p5p_2Lcɣ#;_^Y+qLuH2^M?끁!.p<п|K5ܽN|ܳo2ZC̭{ׇ2?Ο7Z|>+G{O( ģG(Q@< o"mdN f6z(Ŗ ؒoyj{}chP8 62D OpbR[ߤX>6)Ξ_ZD^Z{j'%./%#oѥ4D~+(~fVߒNv\2z;]ha%gN],ՠg|'ŖiiNi?w6M8y>WNMNzөE|מ;\Zk{RxrV8\u8?$W~/ F1ӌoje3+1FmWz7s ؒoSy)ng5ϰE4w!˞rEaT9n>q\hSW=祖%ڲg{j&#gg3!?ٳK3Zm70Qѣ;^+cŚh[vg\>:;_k:wZЫ}V Y/:dEk*^};SiY2j.]/zܭ&ڥc]^.ʄ[f-^/;L8*dh:܇я4{W7lT7nk͛fEj2/]3wv]"?9 v81R??3W^Ûo?E'2DD5v8/%j_C-rOX"ɺ'r5a"ͣ4"o>; ;HɎxV񍋬]\n{ۖ~HrT'Nd "WLD97fMyjUJg$㙥Z9#;.TZբߦv1rO6u49nӠ}n׋J_,c 1Gi1w!BhLD#rAojGz~S31y$eqN[55;\f5M>;LnxAe$"׶򺤓yx4.;Xi:Rܡ^hKZ3LNꯞz|!Ե<\L}3\ qwMZK94 <5"Fd IwMkwLP3;Y~yӸi݉HQsv}ZqoҾu՞)&ok S"2yJ@ǥ ?Kfv @;lUy ]XҦ7.#Y/\U֒L723 AېXa9b!Х*V[w澋 搶qXnڽm>I0`h ۄ}nJ36;; 2 O-qh 'R|6?,CWɧ&u~9~?uz-G=- ]ׇ{vqڔRl/C޳ϐT7 ~iA~jA>Vq̵=]qrjf7, dJ pbi\ k SplcUQMuE=¶VⷴNsak=_݄xM`THJ=ulXeu5jێhE{wΓ6"AlϴnPhvvm`۸wVk7|b>V)pJ:.۟`l(:YLlMlm mVhs)pvoN{^xz><\{9ߎ:[]  6m"q96jI-z*ljgys'][O`(Öf V'_ڧWWCVOdr ?餇gjz_i&\N~hl_'=ϑ Cc/,mhfztk{ 2 _ {9nFlz/Z|*Zߤ\EƞAv ]lfbͤ΅4X]gijo,=0" S#El%Vn&Es}9\=r9f~#7L T7⇟5,=ԳVêv!0#f395Xg|.NgKٵi%neiVEC&&;YV- +kQx*ebli O=兙uO"g8tpoN{CF,O usGXYN_ȦvPIopx6?r=8^% 386;l's >3/{AC׹7aw6MNh| iC~jJ|ĉ3*@ ,D\@ @ (@ @ ©?ZzL^$@ Q@ G @ $%@ H>9b$ 9ZN=!Z2?+ GZe"85u(aX~Eh{%@x7F=U^>$gKQs?څ}m6/}8v؅a."{>JyU]ޛK\ZOe^>mpVb"3-%w*M)Ԯ76 H'kQqL#>'1~Q1 1PЪ`qmv@H'D,ڻUctAbdrY5'%&!F z tB4﷞a%_V Rij (0XX]5 T=RJSR&ZIƶ!m5u.m[7ħEitq3f.uҜL04SI " u1(e.MP3`g5rӖhaMiYm&TΘƽh6cϷ\~)fE"oz9}9WtjڿG__ $۳qiKሶ] =`kcIDATU-HJhq1m̶m|OP@"W]ַ*-CB E8ӣt;@}@_`Zޚ w읚k&o3PPJjPY}!b9unmu#sF; Xnm00,k@K݆c[a`X@f.M_[m[*Ķƣ!֥m}V7K mK~Vps]tG-wū@ /OCe @@_`g*\aSQMC*tClmI[gG!5J ]lO&-~3y/_b=TFz7,JYpƱQjqȄ}aYx]7yhoz-XŨp6I['1Ly׭^JX=$cJ?ڎ1HW[CK9T: J$%%iI|饤RJsB/\o} eL~Ry̽PGPfb\=F&T܋@Ӫ>D`(f;_G/ ?ڀNrmm0Y]_, 5a%ezJj֥G-7@OK%{vX:6~=R@ |6hf 6ϊh6LzQbful`ϡŒ21P7:!@6Q LDOJw3 =dgy:!kyW 9O5_I`_ licensed website validator. LinkChecker checks links in web documents or full websites. It runs on Python 3 systems, requiring Python 3.9 or later. Visit the project on `GitHub `_. Installation ------------ .. code-block:: console $ pip3 install linkchecker The version in the pip repository may be old, to find out how to get the latest code, plus platform-specific information and other advice see the :doc:`installation document `. Basic usage ------------ To check a URL like *http://www.example.org/myhomepage/* it is enough to execute: .. code-block:: console $ linkchecker http://www.example.org/myhomepage/ This check will validate recursively all pages starting with *http://www.example.org/myhomepage/*. Additionally, all external links pointing outside of *www.example.org* will be checked but not recursed into. Find out more from the manual pages :doc:`man/linkchecker` and :doc:`man/linkcheckerrc`. Features --------- - recursive and multithreaded checking and site crawling - output in colored or normal text, HTML, SQL, CSV, XML or a sitemap graph in different formats - HTTP/1.1, HTTPS, FTP, mailto: and local file links support - restriction of link checking with regular expression filters for URLs - proxy support - username/password authorization for HTTP and FTP - honors robots.txt exclusion protocol - Cookie support - HTML5 support - :ref:`Plugin support ` allowing custom page checks - Different interfaces: command line and web interface Screenshots ------------ .. list-table:: * - .. image:: images/shot1.png :scale: 20% - .. image:: images/shot3.png :scale: 20% * - Commandline interface - WSGI web interface Test suite status ------------------ Linkchecker has extensive unit tests to ensure code quality. `GitHub Actions `_ is used for continuous build and test integration. .. image:: https://github.com/linkchecker/linkchecker/actions/workflows/build.yml/badge.svg?branch=master :alt: Build Status :target: https://github.com/linkchecker/linkchecker/actions/workflows/build.yml Icon ---- The project icon is categories/applications-development-web from `Oxygen icons `_ copyright KDE and licensed under the `GNU LGPL version 3 `_ or later. .. toctree:: :hidden: faq install upgrading man/linkchecker man/linkcheckerrc contributing code_of_conduct code/index linkchecker-10.5.0/doc/src/install.rst000066400000000000000000000003161466565367000176350ustar00rootroot00000000000000Installation ============ If you are upgrading from older versions of LinkChecker you should also read the upgrading documentation stored in :doc:`upgrading`. .. include:: ../install.txt :start-line: 5 linkchecker-10.5.0/doc/src/man/000077500000000000000000000000001466565367000162105ustar00rootroot00000000000000linkchecker-10.5.0/doc/src/man/linkchecker.rst000066400000000000000000000400551466565367000212300ustar00rootroot00000000000000:github_url: https://github.com/linkchecker/linkchecker/blob/master/doc/src/man/linkchecker.rst linkchecker =========== SYNOPSIS -------- **linkchecker** [*options*] [*file-or-url*]... DESCRIPTION ----------- LinkChecker features - recursive and multithreaded checking - output in colored or normal text, HTML, SQL, CSV, XML or a sitemap graph in different formats - support for HTTP/1.1, HTTPS, FTP, mailto: and local file links - restriction of link checking with URL filters - proxy support - username/password authorization for HTTP and FTP - support for robots.txt exclusion protocol - support for Cookies - support for HTML5 - Antivirus check - a command line and web interface EXAMPLES -------- The most common use checks the given domain recursively: .. code-block:: console $ linkchecker http://www.example.com/ Beware that this checks the whole site which can have thousands of URLs. Use the :option:`-r` option to restrict the recursion depth. Don't check URLs with **/secret** in its name. All other links are checked as usual: .. code-block:: console $ linkchecker --ignore-url=/secret mysite.example.com Checking a local HTML file on Unix: .. code-block:: console $ linkchecker ../bla.html Checking a local HTML file on Windows: .. code-block:: doscon C:\> linkchecker c:empest.html You can skip the **http://** url part if the domain starts with **www.**: .. code-block:: console $ linkchecker www.example.com You can skip the **ftp://** url part if the domain starts with **ftp.**: .. code-block:: console $ linkchecker -r0 ftp.example.com Generate a sitemap graph and convert it with the graphviz dot utility: .. code-block:: console $ linkchecker -odot -v www.example.com | dot -Tps > sitemap.ps OPTIONS ------- General options ^^^^^^^^^^^^^^^ .. option:: -f FILENAME, --config=FILENAME Use FILENAME as configuration file. By default LinkChecker uses $XDG_CONFIG_HOME/linkchecker/linkcheckerrc. .. option:: -h, --help Help me! Print usage information for this program. .. option:: -t NUMBER, --threads=NUMBER Generate no more than the given number of threads. Default number of threads is 10. To disable threading specify a non-positive number. .. option:: -V, --version Print version and exit. .. option:: --list-plugins Print available check plugins and exit. Output options ^^^^^^^^^^^^^^ URL checking results """""""""""""""""""" .. option:: -F TYPE[/ENCODING][/FILENAME], --file-output=TYPE[/ENCODING][/FILENAME] Output to a file linkchecker-out.TYPE, $XDG_DATA_HOME/linkchecker/failures for the failures output type, or FILENAME if specified. The ENCODING specifies the output encoding, the default is that of your locale. Valid encodings are listed at https://docs.python.org/library/codecs.html#standard-encodings. The FILENAME and ENCODING parts of the none output type will be ignored, else if the file already exists, it will be overwritten. You can specify this option more than once. Valid file output TYPEs are text, html, sql, csv, gml, dot, xml, sitemap, none or failures. Default is no file output. The various output types are documented below. Note that you can suppress all console output with the option :option:`-o` *none*. .. option:: --no-warnings Don't log warnings. Default is to log warnings. .. option:: -o TYPE[/ENCODING], --output=TYPE[/ENCODING] Specify the console output type as text, html, sql, csv, gml, dot, xml, sitemap, none or failures. Default type is text. The various output types are documented below. The ENCODING specifies the output encoding, the default is that of your locale. Valid encodings are listed at https://docs.python.org/library/codecs.html#standard-encodings. .. option:: -v, --verbose Log all checked URLs, overriding :option:`--no-warnings`. Default is to log only errors and warnings. Progress updates """""""""""""""" .. option:: --no-status Do not print URL check status messages. Application """"""""""" .. option:: -D STRING, --debug=STRING Print debugging output for the given logger. Available debug loggers are cmdline, checking, cache, plugin and all. all is an alias for all available loggers. This option can be given multiple times to debug with more than one logger. Quiet """"" .. option:: -q, --quiet Quiet operation, an alias for :option:`-o` *none* that also hides application information messages. This is only useful with :option:`-F`, else no results will be output. Checking options ^^^^^^^^^^^^^^^^ .. option:: --cookiefile=FILENAME Use initial cookie data read from a file. The cookie data format is explained below. .. option:: --check-extern Check external URLs. .. option:: --ignore-url=REGEX URLs matching the given regular expression will only be syntax checked. This option can be given multiple times. See section `REGULAR EXPRESSIONS`_ for more info. .. option:: --no-follow-url=REGEX Check but do not recurse into URLs matching the given regular expression. This option can be given multiple times. See section `REGULAR EXPRESSIONS`_ for more info. .. option:: --no-robots Check URLs regardless of any robots.txt files. .. option:: -p, --password Read a password from console and use it for HTTP and FTP authorization. For FTP the default password is anonymous@. For HTTP there is no default password. See also :option:`-u`. .. option:: -r NUMBER, --recursion-level=NUMBER Check recursively all links up to given depth. A negative depth will enable infinite recursion. Default depth is infinite. .. option:: --timeout=NUMBER Set the timeout for connection attempts in seconds. The default timeout is 60 seconds. .. option:: -u STRING, --user=STRING Try the given username for HTTP and FTP authorization. For FTP the default username is anonymous. For HTTP there is no default username. See also :option:`-p`. .. option:: --user-agent=STRING Specify the User-Agent string to send to the HTTP server, for example "Mozilla/4.0". The default is "LinkChecker/X.Y" where X.Y is the current version of LinkChecker. Input options ^^^^^^^^^^^^^ .. option:: --stdin Read from stdin a list of white-space separated URLs to check. .. option:: FILE-OR-URL The location to start checking with. A file can be a simple list of URLs, one per line, if the first line is "# LinkChecker URL list". CONFIGURATION FILES ------------------- Configuration files can specify all options above. They can also specify some options that cannot be set on the command line. See :manpage:`linkcheckerrc(5)` for more info. OUTPUT TYPES ------------ Note that by default only errors and warnings are logged. You should use the option :option:`--verbose` to get the complete URL list, especially when outputting a sitemap graph format. **text** Standard text logger, logging URLs in keyword: argument fashion. **html** Log URLs in keyword: argument fashion, formatted as HTML. Additionally has links to the referenced pages. Invalid URLs have HTML and CSS syntax check links appended. **csv** Log check result in CSV format with one URL per line. **gml** Log parent-child relations between linked URLs as a GML sitemap graph. **dot** Log parent-child relations between linked URLs as a DOT sitemap graph. **gxml** Log check result as a GraphXML sitemap graph. **xml** Log check result as machine-readable XML. **sitemap** Log check result as an XML sitemap whose protocol is documented at https://www.sitemaps.org/protocol.html. **sql** Log check result as SQL script with INSERT commands. An example script to create the initial SQL table is included as create.sql. **failures** Suitable for cron jobs. Logs the check result into a file **$XDG_DATA_HOME/linkchecker/failures** which only contains entries with invalid URLs and the number of times they have failed. **none** Logs nothing. Suitable for debugging or checking the exit code. REGULAR EXPRESSIONS ------------------- LinkChecker accepts Python regular expressions. See https://docs.python.org/howto/regex.html for an introduction. An addition is that a leading exclamation mark negates the regular expression. COOKIE FILES ------------ A cookie file contains standard HTTP header (RFC 2616) data with the following possible names: **Host** (required) Sets the domain the cookies are valid for. **Path** (optional) Gives the path the cookies are value for; default path is **/**. **Set-cookie** (required) Set cookie name/value. Can be given more than once. Multiple entries are separated by a blank line. The example below will send two cookies to all URLs starting with **http://example.com/hello/** and one to all URLs starting with **https://example.org/**: :: Host: example.com Path: /hello Set-cookie: ID="smee" Set-cookie: spam="egg" :: Host: example.org Set-cookie: baggage="elitist"; comment="hologram" PROXY SUPPORT ------------- To use a proxy on Unix or Windows set the :envvar:`http_proxy` or :envvar:`https_proxy` environment variables to the proxy URL. The URL should be of the form **http://**\ [*user*\ **:**\ *pass*\ **@**]\ *host*\ [**:**\ *port*]. LinkChecker also detects manual proxy settings of Internet Explorer under Windows systems. On a Mac use the Internet Config to select a proxy. You can also set a comma-separated domain list in the :envvar:`no_proxy` environment variable to ignore any proxy settings for these domains. The :envvar:`curl_ca_bundle` environment variable can be used to identify an alternative certificate bundle to be used with an HTTPS proxy. Setting a HTTP proxy on Unix for example looks like this: .. code-block:: console $ export http_proxy="http://proxy.example.com:8080" Proxy authentication is also supported: .. code-block:: console $ export http_proxy="http://user1:mypass@proxy.example.org:8081" Setting a proxy on the Windows command prompt: .. code-block:: doscon C:\> set http_proxy=http://proxy.example.com:8080 PERFORMED CHECKS ---------------- All URLs have to pass a preliminary syntax test. Minor quoting mistakes will issue a warning, all other invalid syntax issues are errors. After the syntax check passes, the URL is queued for connection checking. All connection check types are described below. HTTP links (**http:**, **https:**) After connecting to the given HTTP server the given path or query is requested. All redirections are followed, and if user/password is given it will be used as authorization when necessary. All final HTTP status codes other than 2xx are errors. HTML page contents are checked for recursion. Local files (**file:**) A regular, readable file that can be opened is valid. A readable directory is also valid. All other files, for example device files, unreadable or non-existing files are errors. HTML or other parseable file contents are checked for recursion. Mail links (**mailto:**) A mailto: link eventually resolves to a list of email addresses. If one address fails, the whole list will fail. For each mail address we check the following things: 1. Check the address syntax, both the parts before and after the @ sign. 2. Look up the MX DNS records. If we found no MX record, print an error. 3. Check if one of the mail hosts accept an SMTP connection. Check hosts with higher priority first. If no host accepts SMTP, we print a warning. 4. Try to verify the address with the VRFY command. If we got an answer, print the verified address as an info. FTP links (**ftp:**) For FTP links we do: 1. connect to the specified host 2. try to login with the given user and password. The default user is **anonymous**, the default password is **anonymous@**. 3. try to change to the given directory 4. list the file with the NLST command Unsupported links (**javascript:**, etc.) An unsupported link will only print a warning. No further checking will be made. The complete list of recognized, but unsupported links can be found in the `linkcheck/checker/unknownurl.py `__ source file. The most prominent of them should be JavaScript links. SITEMAPS -------- Sitemaps are parsed for links to check and can be detected either from a sitemap entry in a robots.txt, or when passed as a :option:`FILE-OR-URL` argument in which case detection requires the urlset/sitemapindex tag to be within the first 70 characters of the sitemap. Compressed sitemap files are not supported. PLUGINS ------- There are two plugin types: connection and content plugins. Connection plugins are run after a successful connection to the URL host. Content plugins are run if the URL type has content (mailto: URLs have no content for example) and if the check is not forbidden (ie. by HTTP robots.txt). Use the option :option:`--list-plugins` for a list of plugins and their documentation. All plugins are enabled via the :manpage:`linkcheckerrc(5)` configuration file. RECURSION --------- Before descending recursively into a URL, it has to fulfill several conditions. They are checked in this order: 1. A URL must be valid. 2. A URL must be parseable. This currently includes HTML files, Opera bookmarks files, and directories. If a file type cannot be determined (for example it does not have a common HTML file extension, and the content does not look like HTML), it is assumed to be non-parseable. 3. The URL content must be retrievable. This is usually the case except for example mailto: or unknown URL types. 4. The maximum recursion level must not be exceeded. It is configured with the :option:`--recursion-level` option and is unlimited per default. 5. It must not match the ignored URL list. This is controlled with the :option:`--ignore-url` option. 6. The Robots Exclusion Protocol must allow links in the URL to be followed recursively. This is checked by searching for a "nofollow" directive in the HTML header data. Note that the directory recursion reads all files in that directory, not just a subset like **index.htm**. NOTES ----- URLs on the commandline starting with **ftp.** are treated like **ftp://ftp.**, URLs starting with **www.** are treated like **http://www.**. You can also give local files as arguments. If you have your system configured to automatically establish a connection to the internet (e.g. with diald), it will connect when checking links not pointing to your local host. Use the :option:`--ignore-url` option to prevent this. Javascript links are not supported. If your platform does not support threading, LinkChecker disables it automatically. You can supply multiple user/password pairs in a configuration file. ENVIRONMENT ----------- .. envvar:: http_proxy specifies default HTTP proxy server .. envvar:: https_proxy specifies default HTTPS proxy server .. envvar:: curl_ca_bundle an alternative certificate bundle to be used with an HTTPS proxy .. envvar:: no_proxy comma-separated list of domains to not contact over a proxy server .. envvar:: LC_MESSAGES, LANG, LANGUAGE specify output language RETURN VALUE ------------ The return value is 2 when - a program error occurred. The return value is 1 when - invalid links were found or - link warnings were found and warnings are enabled Else the return value is zero. LIMITATIONS ----------- LinkChecker consumes memory for each queued URL to check. With thousands of queued URLs the amount of consumed memory can become quite large. This might slow down the program or even the whole system. FILES ----- **$XDG_CONFIG_HOME/linkchecker/linkcheckerrc** - default configuration file **$XDG_DATA_HOME/linkchecker/failures** - default failures logger output filename **linkchecker-out.**\ *TYPE* - default logger file output name SEE ALSO -------- :manpage:`linkcheckerrc(5)` https://docs.python.org/library/codecs.html#standard-encodings - valid output encodings https://docs.python.org/howto/regex.html - regular expression documentation linkchecker-10.5.0/doc/src/man/linkcheckerrc.rst000066400000000000000000000514741466565367000215640ustar00rootroot00000000000000:github_url: https://github.com/linkchecker/linkchecker/blob/master/doc/src/man/linkcheckerrc.rst linkcheckerrc ============= DESCRIPTION ----------- **linkcheckerrc** is the configuration file for LinkChecker. The file is written in an INI-style format. The default file location is **$XDG_CONFIG_HOME/linkchecker/linkcheckerrc** or else **~/.config/linkchecker/linkcheckerrc** on Unix, **%HOMEPATH%\\.config\\linkchecker\\linkcheckerrc** on Windows systems. SETTINGS -------- checking ^^^^^^^^ **cookiefile=**\ *filename* Read a file with initial cookie data. The cookie data format is explained in :manpage:`linkchecker(1)`. Command line option: :option:`--cookiefile` **debugmemory=**\ [**0**\ \|\ **1**] Write memory allocation statistics to a file on exit, requires :pypi:`meliae`. The default is not to write the file. Command line option: none **localwebroot=**\ *STRING* When checking absolute URLs inside local files, the given root directory is used as base URL. Note that the given directory must have URL syntax, so it must use a slash to join directories instead of a backslash. And the given directory must end with a slash. Command line option: none **recursionlevel=**\ *NUMBER* Check recursively all links up to given depth. A negative depth will enable infinite recursion. Default depth is infinite. Command line option: :option:`--recursion-level` **threads=**\ *NUMBER* Generate no more than the given number of threads. Default number of threads is 10. To disable threading specify a non-positive number. Command line option: :option:`--threads` **timeout=**\ *NUMBER* Set the timeout for connection attempts in seconds. The default timeout is 60 seconds. Command line option: :option:`--timeout` **aborttimeout=**\ *NUMBER* Time to wait for checks to finish after the user aborts the first time (with Ctrl-C or the abort button). The default abort timeout is 300 seconds. Command line option: none **useragent=**\ *STRING* Specify the User-Agent string to send to the HTTP server, for example "Mozilla/4.0". The default is "LinkChecker/X.Y" where X.Y is the current version of LinkChecker. Command line option: :option:`--user-agent` **sslverify=**\ [**0**\ \|\ **1**\ \|\ *filename*] If set to zero disables SSL certificate checking. If set to one (the default) enables SSL certificate checking with the provided CA certificate file. If a filename is specified, it will be used as the certificate file. Command line option: none **maxrunseconds=**\ *NUMBER* Stop checking new URLs after the given number of seconds. Same as if the user stops (by hitting Ctrl-C) after the given number of seconds. The default is not to stop until all URLs are checked. Command line option: none **maxfilesizedownload=**\ *NUMBER* Files larger than NUMBER bytes will be ignored, without downloading anything if accessed over http and an accurate Content-Length header was returned. No more than this amount of a file will be downloaded. The default is 5242880 (5 MB). Command line option: none **maxfilesizeparse=**\ *NUMBER* Files larger than NUMBER bytes will not be parsed for links. The default is 1048576 (1 MB). Command line option: none **maxnumurls=**\ *NUMBER* Maximum number of URLs to check. New URLs will not be queued after the given number of URLs is checked. The default is to queue and check all URLs. Command line option: none **maxrequestspersecond=**\ *NUMBER* Limit the maximum number of HTTP requests per second to one host. The average number of requests per second is approximately one third of the maximum. Values less than 1 and at least 0.001 can be used. To use values greater than 10, the HTTP server must return a **LinkChecker** response header. The default is 10. Command line option: none **robotstxt=**\ [**0**\ \|\ **1**] When using http, fetch robots.txt, and confirm whether each URL should be accessed before checking. The default is to use robots.txt files. Command line option: :option:`--no-robots` **allowedschemes=**\ *NAME*\ [**,**\ *NAME*...] Allowed URL schemes as comma-separated list. Command line option: none **resultcachesize=**\ *NUMBER* Set the result cache size. The default is 100 000 URLs. Command line option: none filtering ^^^^^^^^^ **ignore=**\ *REGEX* (`MULTILINE`_) Only check syntax of URLs matching the given regular expressions. Command line option: :option:`--ignore-url` **ignorewarnings=**\ *NAME*\ [**,**\ *NAME*...] Ignore the comma-separated list of warnings. See `WARNINGS`_ for the list of supported warnings. Messages are logged as information. Command line option: none **ignorewarningsforurls=**\ *URL_REGEX* [*NAME_REGEX*] (`MULTILINE`_) Specify regular expressions to ignore warnings for matching URLs, one per line. On each line, you can specify a second regular expression, ensuring that only the warnings with names matching the second expression will be ignored for that URL. If the second expression is omitted, all warnings are ignored for that URL. Default is to not ignore any warnings. See `WARNINGS`_ for the list of supported warnings. Messages are logged as information. Command line option: none Example: :: [filtering] ignorewarningsforurls= ^https://redirected\.example\.com ^http-redirected **internlinks=**\ *REGEX* Regular expression to add more URLs recognized as internal links. Default is that URLs given on the command line are internal. Command line option: none **nofollow=**\ *REGEX* (`MULTILINE`_) Check but do not recurse into URLs matching the given regular expressions. Command line option: :option:`--no-follow-url` **checkextern=**\ [**0**\ \|\ **1**] Check external links. Default is to check internal links only. Command line option: :option:`--check-extern` authentication ^^^^^^^^^^^^^^ **entry=**\ *REGEX* *USER* [*PASS*] (`MULTILINE`_) Provide individual username/password pairs for different links. In addition to a single login page specified with **loginurl** multiple FTP and HTTP (Basic Authentication) links are supported. Entries are a triple (URL regex, username, password) or a tuple (URL regex, username), where the entries are separated by whitespace. The password is optional and if missing it has to be entered at the commandline. If the regular expression matches the checked URL, the given username/password pair is used for authentication. The command line options :option:`-u` and :option:`-p` match every link and therefore override the entries given here. The first match wins. Command line option: :option:`-u`, :option:`-p` **loginurl=**\ *URL* The URL of a login page to be visited before link checking. The page is expected to contain an HTML form to collect credentials and submit them to the address in its action attribute using an HTTP POST request. The name attributes of the input elements of the form and the values to be submitted need to be available (see **entry** for an explanation of username and password values). **loginuserfield=**\ *STRING* The name attribute of the username input element. Default: **login**. **loginpasswordfield=**\ *STRING* The name attribute of the password input element. Default: **password**. **loginextrafields=**\ *NAME*\ **:**\ *VALUE* (`MULTILINE`_) Optionally the name attributes of any additional input elements and the values to populate them with. Note that these are submitted without checking whether matching input elements exist in the HTML form. output ^^^^^^ URL checking results """""""""""""""""""" **fileoutput=**\ *TYPE*\ [**,**\ *TYPE*...] Output to a file **linkchecker-out.**\ *TYPE*, or **$XDG_DATA_HOME/linkchecker/failures** for the **failures** output type. Valid file output types are **text**, **html**, **sql**, **csv**, **gml**, **dot**, **xml**, **none** or **failures**. Default is no file output. The various output types are documented below. Note that you can suppress all console output with **output=none**. Command line option: :option:`--file-output` **log=**\ *TYPE*\ [**/**\ *ENCODING*] Specify the console output type as **text**, **html**, **sql**, **csv**, **gml**, **dot**, **xml**, **none** or **failures**. Default type is **text**. The various output types are documented below. The *ENCODING* specifies the output encoding, the default is that of your locale. Valid encodings are listed at https://docs.python.org/library/codecs.html#standard-encodings. Command line option: :option:`--output` **verbose=**\ [**0**\ \|\ **1**] If set log all checked URLs once, overriding **warnings**. Default is to log only errors and warnings. Command line option: :option:`--verbose` **warnings=**\ [**0**\ \|\ **1**] If set log warnings. Default is to log warnings. Command line option: :option:`--no-warnings` **ignoreerrors=**\ *URL_REGEX* [*MESSAGE_REGEX*] (`MULTILINE`_) Specify regular expressions to ignore errors for matching URLs, one per line. A second regular expression can be specified per line to only ignore matching error messages per corresponding URL. If the second expression is omitted, all errors are ignored. In contrast to filtering_, this happens *after* checking, which allows checking URLs despite certain expected and tolerable errors. Default is to not ignore any errors. Example: :: [output] ignoreerrors= ^https://deprecated\.example\.com ^410 Gone # ignore all errors (no second expression), also for syntax check: ^mailto:.*@example\.com$ Progress updates """""""""""""""" **status=**\ [**0**\ \|\ **1**] Control printing URL checker status messages. Default is 1. Command line option: :option:`--no-status` Application """"""""""" **debug=**\ *STRING*\ [**,**\ *STRING*...] Print debugging output for the given logger. Available debug loggers are **cmdline**, **checking**, **cache**, **plugin** and **all**. **all** is an alias for all available loggers. Command line option: :option:`--debug` Quiet """"" **quiet=**\ [**0**\ \|\ **1**] If set, operate quiet. An alias for **log=none** that also hides application information messages. This is only useful with **fileoutput**, else no results will be output. Command line option: :option:`--quiet` OUTPUT TYPES ------------ text ^^^^ **filename=**\ *STRING* Specify output filename for text logging. Default filename is **linkchecker-out.txt**. Command line option: :option:`--file-output` **parts=**\ *STRING* Comma-separated list of parts that have to be logged. See `LOGGER PARTS`_ below. Command line option: none **encoding=**\ *STRING* Valid encodings are listed in https://docs.python.org/library/codecs.html#standard-encodings. Default encoding is the system default locale encoding. **wraplength=**\ *NUMBER* The number of characters at which to wrap each message line. The default is 65. Command line option: none *color\** Color settings for the various log parts, syntax is *color* or *type*\ **;**\ *color*. The *type* can be **bold**, **light**, **blink**, **invert**. The *color* can be **default**, **black**, **red**, **green**, **yellow**, **blue**, **purple**, **cyan**, **white**, **Black**, **Red**, **Green**, **Yellow**, **Blue**, **Purple**, **Cyan** or **White**. Command line option: none **colorparent=**\ *STRING* Set parent color. Default is **white**. **colorurl=**\ *STRING* Set URL color. Default is **default**. **colorname=**\ *STRING* Set name color. Default is **default**. **colorreal=**\ *STRING* Set real URL color. Default is **cyan**. **colorbase=**\ *STRING* Set base URL color. Default is **purple**. **colorvalid=**\ *STRING* Set valid color. Default is **bold;green**. **colorinvalid=**\ *STRING* Set invalid color. Default is **bold;red**. **colorinfo=**\ *STRING* Set info color. Default is **default**. **colorwarning=**\ *STRING* Set warning color. Default is **bold;yellow**. **colordltime=**\ *STRING* Set download time color. Default is **default**. **colorreset=**\ *STRING* Set reset color. Default is **default**. gml ^^^ **filename=**\ *STRING* See :ref:`[text] ` section above. **parts=**\ *STRING* See :ref:`[text] ` section above. **encoding=**\ *STRING* See :ref:`[text] ` section above. dot ^^^ **filename=**\ *STRING* See :ref:`[text] ` section above. **parts=**\ *STRING* See :ref:`[text] ` section above. **encoding=**\ *STRING* See :ref:`[text] ` section above. csv ^^^ **filename=**\ *STRING* See :ref:`[text] ` section above. **parts=**\ *STRING* See :ref:`[text] ` section above. **encoding=**\ *STRING* See :ref:`[text] ` section above. **separator=**\ *CHAR* Set CSV separator. Default is a semicolon (**;**). **quotechar=**\ *CHAR* Set CSV quote character. Default is a double quote (**"**). **dialect=**\ *STRING* Controls the output formatting. See https://docs.python.org/3/library/csv.html#csv.Dialect. Default is **excel**. sql ^^^ **filename=**\ *STRING* See :ref:`[text] ` section above. **parts=**\ *STRING* See :ref:`[text] ` section above. **encoding=**\ *STRING* See :ref:`[text] ` section above. **dbname=**\ *STRING* Set database name to store into. Default is **linksdb**. **separator=**\ *CHAR* Set SQL command separator character. Default is a semicolon (**;**). html ^^^^ **filename=**\ *STRING* See :ref:`[text] ` section above. **parts=**\ *STRING* See :ref:`[text] ` section above. **encoding=**\ *STRING* See :ref:`[text] ` section above. **colorbackground=**\ *COLOR* Set HTML background color. Default is **#fff7e5**. **colorurl=** Set HTML URL color. Default is **#dcd5cf**. **colorborder=** Set HTML border color. Default is **#000000**. **colorlink=** Set HTML link color. Default is **#191c83**. **colorwarning=** Set HTML warning color. Default is **#e0954e**. **colorerror=** Set HTML error color. Default is **#db4930**. **colorok=** Set HTML valid color. Default is **#3ba557**. failures ^^^^^^^^^ **filename=**\ *STRING* See :ref:`[text] ` section above. **encoding=**\ *STRING* See :ref:`[text] ` section above. xml ^^^ **filename=**\ *STRING* See :ref:`[text] ` section above. **parts=**\ *STRING* See :ref:`[text] ` section above. **encoding=**\ *STRING* See :ref:`[text] ` section above. gxml ^^^^ **filename=**\ *STRING* See :ref:`[text] ` section above. **parts=**\ *STRING* See :ref:`[text] ` section above. **encoding=**\ *STRING* See :ref:`[text] ` section above. sitemap ^^^^^^^ **filename=**\ *STRING* See :ref:`[text] ` section above. **parts=**\ *STRING* See :ref:`[text] ` section above. **encoding=**\ *STRING* See :ref:`[text] ` section above. **priority=**\ *FLOAT* A number between 0.0 and 1.0 determining the priority. The default priority for the first URL is 1.0, for all child URLs 0.5. **frequency=**\ [**always**\ \|\ **hourly**\ \|\ **daily**\ \|\ **weekly**\ \|\ **monthly**\ \|\ **yearly**\ \|\ **never**] How frequently pages are changing. Default is **daily**. LOGGER PARTS ------------ **all** for all parts **id** a unique ID for each logentry **realurl** the full url link **result** valid or invalid, with messages **extern** 1 or 0, only in some logger types reported **base** base href=... **name** name and name **parenturl** if any **info** some additional info, e.g. FTP welcome messages **warning** warnings **dltime** download time **checktime** check time **url** the original url name, can be relative **intro** the blurb at the beginning, "starting at ..." **outro** the blurb at the end, "found x errors ..." MULTILINE --------- Some option values can span multiple lines. Each line has to be indented for that to work. Lines starting with a hash (**#**) will be ignored, though they must still be indented. :: ignore= lconline bookmark # a comment ^mailto: EXAMPLE ------- :: [output] log=html [checking] threads=5 [filtering] ignorewarnings=http-moved-permanent PLUGINS ------- All plugins have a separate section. If the section appears in the configuration file the plugin is enabled. Some plugins read extra options in their section. AnchorCheck ^^^^^^^^^^^ Checks validity of HTML anchors. When checking local files, URLs with anchors that link to directories e.g. "example/#anchor" are not supported. There is no such limitation when using http(s). LocationInfo ^^^^^^^^^^^^ Adds the country and if possible city name of the URL host as info. Needs GeoIP or pygeoip and a local country or city lookup DB installed. RegexCheck ^^^^^^^^^^ Define a regular expression which prints a warning if it matches any content of the checked link. This applies only to valid pages, so we can get their content. **warningregex=**\ *REGEX* Use this to check for pages that contain some form of error message, for example "This page has moved" or "Oracle Application error". *REGEX* should be unquoted. Note that multiple values can be combined in the regular expression, for example "(This page has moved\|Oracle Application error)". SslCertificateCheck ^^^^^^^^^^^^^^^^^^^ Check SSL certificate expiration date. Only internal https: links will be checked. A domain will only be checked once to avoid duplicate warnings. **sslcertwarndays=**\ *NUMBER* Configures the expiration warning time in days. HtmlSyntaxCheck ^^^^^^^^^^^^^^^ Check the syntax of HTML pages by submitting their URLs to the online W3C HTML validator. If a page URL is not accessible to the validator no check is performed and no warning given. See https://validator.w3.org/docs/api.html. .. note:: The HtmlSyntaxCheck plugin is currently broken and is disabled. HttpHeaderInfo ^^^^^^^^^^^^^^ Print HTTP headers in URL info. **prefixes=**\ *prefix1*\ [,*prefix2*]... List of comma separated header prefixes. For example to display all HTTP headers that start with "X-". CssSyntaxCheck ^^^^^^^^^^^^^^ Check the syntax of CSS stylesheets by submitting their URLs to the online W3C CSS validator. If a stylesheet URL is not accessible to the validator no check is performed and no warning given. See https://jigsaw.w3.org/css-validator/manual.html#expert. VirusCheck ^^^^^^^^^^ Checks the page content for virus infections with clamav. A local clamav daemon must be installed. **clamavconf=**\ *filename* Filename of **clamd.conf** config file. PdfParser ^^^^^^^^^ Parse PDF files for URLs to check. Needs the :pypi:`pdfminer.six` Python package installed. WordParser ^^^^^^^^^^ Parse Word files for URLs to check. Needs the :pypi:`pywin32` Python extension installed. MarkdownCheck ^^^^^^^^^^^^^ Parse Markdown files for URLs to check. **filename_re=**\ *REGEX* Regular expression matching the names of Markdown files. WARNINGS -------- The following warnings are recognized by **ignorewarnings** and **ignorewarningsforurls**: **file-anchorcheck-directory** A local directory with an anchor, not supported by AnchorCheck. **file-missing-slash** The file: URL is missing a trailing slash. **file-system-path** The file: path is not the same as the system specific path. **ftp-missing-slash** The ftp: URL is missing a trailing slash. **http-cookie-store-error** An error occurred while storing a cookie. **http-empty-content** The URL had no content. **http-rate-limited** Too many HTTP requests. **http-redirected** Redirected to a different URL. **mail-no-mx-host** The mail MX host could not be found. **url-content-size-zero** The URL content size is zero. **url-content-too-large** The URL content size is too large. **url-content-type-unparseable** The URL content type is not parseable. **url-effective-url** The effective URL is different from the original. **url-error-getting-content** Could not get the content of the URL. **url-obfuscated-ip** The IP is obfuscated. **url-whitespace** The URL contains leading or trailing whitespace. SEE ALSO -------- :manpage:`linkchecker(1)` linkchecker-10.5.0/doc/src/upgrading.rst000066400000000000000000000000361466565367000201460ustar00rootroot00000000000000.. include:: ../upgrading.txt linkchecker-10.5.0/doc/translations.md000066400000000000000000000025021466565367000177100ustar00rootroot00000000000000LinkChecker Translations ======================== Translations for the application are stored in po/. Translations for the man pages are stored in doc/. Application Translations ------------------------ Makefiles using GNU gettext utilities are provided to manage .po and .pot files. If the strings in the application change, update the .pot and .po files: ``linkchecker/po $ rm linkchecker.pot; make`` Do make a commit at this point. Translation progress and validity can be monitored with: ``linkchecker/po $ make check`` .mo files are not stored in the repository and are created on building, using polib. Man Page Translations --------------------- Sphinx is used to generate .pot and .po (with sphinx-intl) files in i18n/ and man pages in man/. If the application metadata has not been created, first run: ``linkchecker $ hatchling build -t sdist --hooks-only`` Create man.pot file in i18n/gettext/: ``linkchecker/doc $ make -C src gettext`` Create man.po file in i18n/locales/: ``linkchecker/doc/src $ sphinx-intl update -p ../i18n/gettext -l de`` These two steps can be performed with: ``linkchecker/doc $ make locale`` Create man pages: ``linkchecker/doc $ make man`` After updating the source files all steps need to be repeated, if translations alone have been changed in the .po file only the last step is needed. linkchecker-10.5.0/doc/upgrading.txt000066400000000000000000000252411466565367000173730ustar00rootroot00000000000000Upgrading ========= Migrating from 10.4 to 10.5 --------------------------- No action needed. Migrating from 10.3 to 10.4 --------------------------- Python 3.9 or newer is required. Migrating from 10.2 to 10.3 --------------------------- Python 3.8 or newer is required. An HTTP redirect now causes a warning. Set ignorewarnings=http-redirected in linkcheckerrc for the previous behaviour. Migrating from 10.1 to 10.2 --------------------------- Python 3.7 or newer is required. Compiled application translations are now also included in the sdist package. No need to install polib before installing any distribution package. It is still required for building distribution packages that include translations. Warning url-rate-limited renamed to http-rate-limited. Migrating from 10.0 to 10.1 --------------------------- If installing from source and application translations are needed the Python polib package is required to be installed before LinkChecker is installed. The linkchecker command is now generated using an entry point: for Python 3.6 and 3.7 importlib_metadata is added to the run-time requirements. The environment variable ftp_proxy is no longer supported. GNOME and KDE proxy settings are not read; KDE proxy users especially may need to set the http_proxy environment variable themselves. Migrating from 9.x to 10.0 -------------------------- Python 3.6 or newer is required. The Python Beautiful Soup package is now required. A C compiler is not needed for building. The loginuserfield and loginpasswordfield entries in the authentication section of linkcheckerrc are now matched to a login form case-sensitively. The "blacklist" logger has been renamed to "failures". "blacklist" is recognised as an alias for "failures" but will be removed in future. Migrating from 8.x to 9.0 ------------------------- The Python requests package is now required. Several checks have been moved to plugins (see below). Plugins have to be enabled in the configuration file. The following commandline and configuration options have been deprecated and do not have any effect: --anchors, anchors: moved to plugin AnchorCheck --check-css, checkcss: moved to plugin CssSyntaxCheck --check-html, checkhtml: moved to plugin HtmlSyntaxCheck --complete: feature removed --cookies, sendcookies, storecookies: cookies are sent/stored per default --pause, wait: replaced with numrequestspersecond --scan-virus, scanvirus: moved to plugin VirusCheck --warning-regex: moved to plugin RegexCheck --warning-size-bytes, warnsizebytes: feature removed warnsslcertdaysvalid: moved to plugin SslCertificationCheck The "html" logger generates HTML5 documents now. The following warnings have been removed: - http-auth-unauthorized: removed - http-auth-unknonwn: removed - http-decompress-error: removed - http-robots-denied: downgraded to info - http-moved-permanent: downgraded to info - http-unsupported-encoding: removed - https-certificate-error: is an error now - mail-unverified-address: removed - mail-no-connection: removed - syntax-css: moved to plugin - syntax-html: moved to plugin - url-anchor-not-found: moved to plugin - url-content-size-unequal: removed - url-warnregex-found: moved to plugin Migrating from 8.4 to 8.5 -------------------------- Custom output loggers have been changed. See doc/web/content/faq.md for an example with custom loggers. Migrating from 8.0 to 8.1 ------------------------- All loggers have an additional output field "modified". If these loggers are not configured with specific output parts, the output format will change. For example existing SQL tables can be altered with: alter table linkcheck add (modified varchar(256)); The default User-Agent string used by LinkChecker is now Mozilla/5.0 (compatible; LinkChecker/8.1; +http://linkchecker.sourceforge.net/) Migrating from 7.9 to 8.0 ------------------------- Python 2.7.2 or newer is required (Python 3.x is not supported though). Migrating from 7.6 to 7.7 ------------------------- The deprecated options --check-html-w3 and --check-css-w3 have been removed from the commandline client. Migrating from 7.3 to 7.4 ------------------------- Python 2.7 or newer is required (Python 3.x is not supported though). The deprecated options --interactive, --priority and --allow-root have been removed from the commandline client. Migrating from 7.0 to 7.1 ------------------------- The FastCGI module lc.fcgi has been removed. The lc.cgi module can be used instead. Migrating from 6.x to 7.0 ------------------------- The system configuration file support has been removed. There is now only one user-configurable configuration file. On Unix systems it is at $HOME/.linkchecker/linkcheckerrc and on Windows systems at %HOMEPATH%\.linkchecker\linkcheckerrc Migrating from 6.6 to 6.7 ------------------------- The machine readable output formats xml, csv and sql now report the recursion level of each URL. Migrating from 6.4 to 6.5 ------------------------- Only applies if a custom output loggers has been programmed: The URL data model for output loggers has changed. The list of warning messages is now a list of tuples (tagname, warningmessage). Migrating from 5.5 to 6.0 ------------------------- Python 2.6 or newer is required (Python 3.x is not supported though). The deprecated --no-proxy-for and --no-anchor-caching options have been removed. The configuration file now requires multiline syntax for the options "nofollow", "ignore" and "entry". Migrating from 5.2 to 5.3 ------------------------- The --password option now reads a password from stdin instead taking it from the commandline. This prevents reading the password from the commandline string with tools like ``ps``. Migrating from 5.1 to 5.2 ------------------------- The --no-proxy-for option has been deprecated and will be removed in a future release. Also, the "noproxyfor" entries in configuration files will not be evaluated anymore. You should use the $no_proxy environment variable instead, which specifies a comma-separated list of domains that are not contacted over proxies. Migrating from 5.0 to 5.1 ------------------------- The --no-anchor-caching option has been deprecated and will be removed in a future release. This option should not be used anymore. The exit code of the linkchecker script will be zero now if all warnings have been ignored. Migrating from 4.x to 5.0 ------------------------- Python >= 2.5 is now required. The CGI script access control has been removed. Please use the access control of your webserver to restrict access to the CGI script. An example configuration file for the Apache weberver has been included in the distribution. Migrating from 4.4 to 4.5 ------------------------- Configuration file entries that were enumerated (``ignoreX``, ``nofollowX``, ``noproxyX`` and ``entryX``) now have a new multiline syntax. For example the old configuration: :: ignore1=^mailto: ignore2=^nntp: should be written as: :: ignore= ^mailto: # this is a comment ^nntp: Note the leading spac(es) at the beginning of each line after ``ignore=``. If an indented line starts with a comment sign, it will be ignored. Migrating from 4.2 to 4.3 ------------------------- The deprecated ``--disable-psyco`` option has been removed. Migrating from 4.1 to 4.2 ------------------------- If run under Unix system as the 'root' user, LinkChecker drops privileges and runs under the 'nobody' user account. The new option --allow-root prevents this, ie. enables the old pre-4.2 behaviour. Migrating from 3.x to 4.0 ------------------------- The Python API of the linkcheck module has changed. If you were using the library directly instead of the commandline or CGI interfaces, you will have to adjust your code. The default intern pattern matches now both http and https. When checking a site ``http://example.com/``, all URLs of the form ``https://example.com/`` will now also be checked recursively. LinkChecker now honors a "Crawl-delay" entry in robots.txt files. The delay makes LinkChecker pause between requests to the corresponding server, so your checking time might increase if the server enforces such a delay through its robots.txt file. URLs with invalid syntax are now cached, and they get matched now by the --ingore-url option. Migrating from 3.0 to 3.1 ------------------------- The ``xml`` output logger has been renamed to ``gxml``. Migrating from 2.x to 3.0 ------------------------- The --warnings option is deprecated since warnings are now printed per default. A new --no-warnings has been added if one wants to have the old behaviour. Additionally, some old warnings about have been removed. The previously deprecated --status option has been removed. The options --intern, --extern and --extern-strict have been replaced by --ignore-url and --no-follow-url. The configuration file format has changed. See the distributed linkcheckerrc default config for the new syntax. Migrating from 2.2 to 2.3 ------------------------- The per-user config file is now ``~/.linkchecker/linkcheckerrc`` (previous location was ``~/.linkcheckerrc`` ). The default blacklist output file is now ``~/.linkchecker/blacklist`` (previous location was ``~/.blacklist``). Python >= 2.4 is now required. Migrating from 1.x to 2.0 ------------------------- The --output and --file-output parameters can specify the encoding now. You should check your scripts if they support the new option syntax. Some added checks might trigger new warnings, so automated scripts or alarms can have more output than with 1.x releases. All output (file and console) is now encoded according to a given character set encoding which defaults to ISO-8859-15. If you relied that output was in a specific encoding, you might want to use the output encoding option. Migrating from 1.12.x to 1.13.0 ------------------------------- Since lots of filenames have changed you should check that any manually installed versions prior to 1.13.0 are removed. Otherwise you will have startup problems. The default output logger ``text`` has now colored output if the output terminal supports it. The old ``colored`` output logger has been removed. The ``-F`` option no longer suppresses normal output. The old behaviour can be restored by giving the option ``-onone``. The --status option is now the default and has been deprecated. The old behaviour can be restored by giving the option ``--no-status``. The default recursion depth is now infinite. The old behaviour can be restored by giving the option ``--recursion-level=1``. The option ``--strict`` has been renamed to ``--extern-strict-all``. The commandline program ``linkchecker`` returns now non-zero exit value when errors were encountered. Previous versions always return a zero exit value. For scripts to ignore exit values and therefore restore the old behaviour you can append a ``|| true`` at the end of the command. linkchecker-10.5.0/linkcheck/000077500000000000000000000000001466565367000160345ustar00rootroot00000000000000linkchecker-10.5.0/linkcheck/__init__.py000066400000000000000000000065161466565367000201550ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Main package for link checking. """ # version checks import sys if sys.version_info < (3, 9, 0, 'final', 0): import platform raise SystemExit( "This program requires Python 3.9 or later instead of %s." % platform.python_version() ) import os import re from . import i18n, log from .logconf import ( LOG_ROOT, LOG_CMDLINE, LOG_CHECK, LOG_CACHE, LOG_THREAD, LOG_PLUGIN, ) COMMAND_NAME = "linkchecker" PACKAGE_NAME = __spec__.parent def module_path(): """Return absolute directory of system executable.""" return os.path.dirname(os.path.abspath(sys.executable)) class LinkCheckerError(Exception): """Exception to be raised on linkchecker-specific check errors.""" pass class LinkCheckerInterrupt(Exception): """Used for testing.""" pass def get_link_pat(arg, strict=False): """Get a link pattern matcher for intern/extern links. Returns a compiled pattern and a negate and strict option. @param arg: pattern from config @type arg: string @param strict: if pattern is to be handled strict @type strict: bool @return: dictionary with keys 'pattern', 'negate' and 'strict' @rtype: dict @raises: re.error on invalid regular expressions """ log.debug(LOG_CHECK, _("Link pattern %r strict=%s"), arg, strict) if arg.startswith('!'): pattern = arg[1:] negate = True else: pattern = arg negate = False try: regex = re.compile(pattern) except re.error as msg: log.warn(LOG_CHECK, _("invalid regular expression %r: %s"), pattern, msg) raise return { "pattern": regex, "negate": negate, "strict": strict, } def init_i18n(): """Initialize i18n with the configured locale dir. The environment variable LOCPATH can also specify a locale dir. @return: None """ if 'LOCPATH' in os.environ: locdir = os.environ['LOCPATH'] else: # Need Python 3.9 for importlib.resources.files locdir = os.path.join(__path__[0], 'data', 'locale') i18n.init(COMMAND_NAME, locdir) # install translated log level names import logging logging.addLevelName(logging.CRITICAL, _('CRITICAL')) logging.addLevelName(logging.ERROR, _('ERROR')) logging.addLevelName(logging.WARN, _('WARN')) logging.addLevelName(logging.WARNING, _('WARNING')) logging.addLevelName(logging.INFO, _('INFO')) logging.addLevelName(logging.DEBUG, _('DEBUG')) logging.addLevelName(logging.NOTSET, _('NOTSET')) # initialize i18n, puts _() and _n() function into global namespace init_i18n() linkchecker-10.5.0/linkcheck/__main__.py000066400000000000000000000000741466565367000201270ustar00rootroot00000000000000from .command.linkchecker import linkchecker linkchecker() linkchecker-10.5.0/linkcheck/ansicolor.py000066400000000000000000000225041466565367000204020ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ ANSI Color definitions and functions. For Windows systems, the colorama module uses ctypes and Windows DLLs to generate colored output. From Term::ANSIColor, applies also to this module: The codes output by this module are standard terminal control codes, complying with ECMA-48 and ISO 6429 (generally referred to as "ANSI color" for the color codes). The non-color control codes (bold, dark, italic, underline, and reverse) are part of the earlier ANSI X3.64 standard for control sequences for video terminals and peripherals. Note that not all displays are ISO 6429-compliant, or even X3.64-compliant (or are even attempting to be so). Jean Delvare provided the following table of different common terminal emulators and their support for the various attributes and others have helped me flesh it out:: clear bold dark under blink reverse conceal ------------------------------------------------------------------------ xterm yes yes no yes bold yes yes linux yes yes yes bold yes yes no rxvt yes yes no yes bold/black yes no dtterm yes yes yes yes reverse yes yes teraterm yes reverse no yes rev/red yes no aixterm kinda normal no yes no yes yes PuTTY yes color no yes no yes no Windows yes no no no no yes no Cygwin SSH yes yes no color color color yes SEE ALSO ECMA-048 is available on-line (at least at the time of this writing) at http://www.ecma-international.org/publications/standards/ECMA-048.HTM. ISO 6429 is available from ISO for a charge; the author of this module does not own a copy of it. Since the source material for ISO 6429 was ECMA-048 and the latter is available for free, there seems little reason to obtain the ISO standard. """ import os import logging import types from .fileutil import has_module, is_tty if os.name == 'nt': from . import colorama has_curses = has_module("curses") # Color constants # Escape for ANSI colors AnsiEsc = "\x1b[%sm" # Control constants bold = 'bold' light = 'light' underline = 'underline' blink = 'blink' invert = 'invert' concealed = 'concealed' # Control numbers AnsiControl = { None: '', bold: '1', light: '2', # italic: '3', # unsupported underline: '4', blink: '5', # rapidblink: '6', # unsupported invert: '7', concealed: '8', # strikethrough: '9', # unsupported } # Color constants default = 'default' black = 'black' red = 'red' green = 'green' yellow = 'yellow' blue = 'blue' purple = 'purple' cyan = 'cyan' white = 'white' # inverse colors Black = 'Black' Red = 'Red' Green = 'Green' Yellow = 'Yellow' Blue = 'Blue' Purple = 'Purple' Cyan = 'Cyna' White = 'White' InverseColors = (Black, Red, Green, Yellow, Blue, Purple, Cyan, White) # Ansi color numbers; capitalized colors are inverse AnsiColor = { None: '0', default: '0', black: '30', red: '31', green: '32', yellow: '33', blue: '34', purple: '35', cyan: '36', white: '37', Black: '40', Red: '41', Green: '42', Yellow: '43', Blue: '44', Purple: '45', Cyan: '46', White: '47', } if os.name == 'nt': # Windows color numbers; capitalized colors are used as background WinColor = { None: None, default: colorama.GREY, black: colorama.BLACK, red: colorama.RED, green: colorama.GREEN, yellow: colorama.YELLOW, blue: colorama.BLUE, purple: colorama.MAGENTA, cyan: colorama.CYAN, white: colorama.GREY, Black: colorama.BLACK, Red: colorama.RED, Green: colorama.GREEN, Yellow: colorama.YELLOW, Blue: colorama.BLUE, Purple: colorama.MAGENTA, Cyan: colorama.CYAN, White: colorama.GREY, } else: WinColor = { None: None, } # pc speaker beep escape code Beep = "\007" def esc_ansicolor(color): """convert a named color definition to an escaped ANSI color""" control = '' if ";" in color: control, color = color.split(";", 1) control = AnsiControl.get(control, '') + ";" cnum = AnsiColor.get(color, '0') return AnsiEsc % (control + cnum) AnsiReset = esc_ansicolor(default) def get_win_color(color): """Convert a named color definition to Windows console color foreground, background and style numbers.""" foreground = background = style = None control = '' if ";" in color: control, color = color.split(";", 1) if control == bold: style = colorama.BRIGHT if color in InverseColors: background = WinColor[color] else: foreground = WinColor.get(color) return foreground, background, style def has_colors(fp): """Test if given file is an ANSI color enabled tty.""" # The is_tty() function ensures that we do not colorize # redirected streams, as this is almost never what we want if not is_tty(fp): return False if os.name == 'nt': return True elif has_curses: import curses try: curses.setupterm(os.environ.get("TERM"), fp.fileno()) # More than 8 colors are good enough. return curses.tigetnum("colors") >= 8 except curses.error: return False return False def get_columns(fp): """Return number of columns for given file.""" if not is_tty(fp): return 80 if os.name == 'nt': return colorama.get_console_size().X if has_curses: import curses try: curses.setupterm(os.environ.get("TERM"), fp.fileno()) return curses.tigetnum("cols") except curses.error: pass return 80 def _write_color_colorama(fp, text, color): """Colorize text with given color.""" foreground, background, style = get_win_color(color) colorama.set_console(foreground=foreground, background=background, style=style) fp.write(text) colorama.reset_console() def _write_color_ansi(fp, text, color): """Colorize text with given color.""" fp.write(esc_ansicolor(color)) fp.write(text) fp.write(AnsiReset) if os.name == 'nt': write_color = _write_color_colorama colorama.init() else: write_color = _write_color_ansi class Colorizer: """Prints colored messages to streams.""" def __init__(self, fp): """Initialize with given stream (file-like object).""" self.fp = fp if has_colors(fp): self.write = self._write_color else: self.write = self._write def _write(self, text, color=None): """Print text as-is.""" self.fp.write(text) def _write_color(self, text, color=None): """Print text with given color. If color is None, print text as-is.""" if color is None: self.fp.write(text) else: write_color(self.fp, text, color) def __getattr__(self, name): """Delegate attribute access to the stored stream object.""" return getattr(self.fp, name) class ColoredStreamHandler(logging.StreamHandler): """Send colored log messages to streams (file-like objects).""" def __init__(self, strm=None): """Log to given stream (a file-like object) or to stderr if strm is None. """ super().__init__(strm) self.stream = Colorizer(self.stream) # standard log level colors (used by get_color) self.colors = { logging.WARN: 'bold;yellow', logging.ERROR: 'light;red', logging.CRITICAL: 'bold;red', logging.DEBUG: 'white', } def get_color(self, record): """Get appropriate color according to log level. """ return self.colors.get(record.levelno, 'default') def emit(self, record): """Emit a record. If a formatter is specified, it is used to format the record. The record is then written to the stream with a trailing newline [N.B. this may be removed depending on feedback]. """ color = self.get_color(record) msg = self.format(record) if not hasattr(types, "UnicodeType"): # no unicode support self.stream.write("%s" % msg, color=color) else: try: self.stream.write("%s" % msg, color=color) except UnicodeError: self.stream.write("%s" % msg.encode("UTF-8"), color=color) self.stream.write(os.linesep) self.flush() linkchecker-10.5.0/linkcheck/better_exchook2.py000066400000000000000000000220571466565367000215030ustar00rootroot00000000000000# # Copyright (c) 2012, Albert Zeyer, www.az2000.de # All rights reserved. # file created 2011-04-15 # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # This is a simple replacement for the standard Python exception handler (sys.excepthook). # In addition to what the standard handler does, it also prints all referenced variables # (no matter if local, global or builtin) of the code line of each stack frame. # See below for some examples and some example output. # https://github.com/albertz/py_better_exchook import sys import os import keyword pykeywords = set(keyword.kwlist) def parse_py_statement(line): state = 0 curtoken = "" spaces = " \t\n" ops = ".,;:+-*/%&=|(){}[]^<>" i = 0 def _escape_char(c): if c == "n": return "\n" elif c == "t": return "\t" else: return c while i < len(line): c = line[i] i += 1 if state == 0: if c in spaces: pass elif c in ops: yield ("op", c) elif c == "#": state = 6 elif c == "\"": state = 1 elif c == "'": state = 2 else: curtoken = c state = 3 elif state == 1: # string via " if c == "\\": state = 4 elif c == "\"": yield ("str", curtoken) curtoken = "" state = 0 else: curtoken += c elif state == 2: # string via ' if c == "\\": state = 5 elif c == "'": yield ("str", curtoken) curtoken = "" state = 0 else: curtoken += c elif state == 3: # identifier if c in spaces + ops + "#\"'": yield ("id", curtoken) curtoken = "" state = 0 i -= 1 else: curtoken += c elif state == 4: # escape in " curtoken += _escape_char(c) state = 1 elif state == 5: # escape in ' curtoken += _escape_char(c) state = 2 elif state == 6: # comment curtoken += c if state == 3: yield ("id", curtoken) elif state == 6: yield ("comment", curtoken) def grep_full_py_identifiers(tokens): global pykeywords tokens = list(tokens) i = 0 while i < len(tokens): tokentype, token = tokens[i] i += 1 if tokentype != "id": continue while i+1 < len(tokens) and tokens[i] == ("op", ".") and tokens[i+1][0] == "id": token += "." + tokens[i+1][1] i += 2 if token == "": continue if token in pykeywords: continue if token[0] in ".0123456789": continue yield token def output(s, out=sys.stdout): print(s, file=out) def output_limit(): return 300 def pp_extra_info(obj, depthlimit = 3): s = [] if hasattr(obj, "__len__"): try: if type(obj) in (bytes,str,list,tuple,dict) and len(obj) <= 5: pass # don't print len in this case else: s += ["len = " + str(obj.__len__())] except Exception: pass if depthlimit > 0 and hasattr(obj, "__getitem__"): try: if type(obj) in (bytes,str): pass # doesn't make sense to get subitems here else: subobj = obj.__getitem__(0) extra_info = pp_extra_info(subobj, depthlimit - 1) if extra_info != "": s += ["_[0]: {" + extra_info + "}"] except Exception: pass return ", ".join(s) def pretty_print(obj): s = repr(obj) limit = output_limit() if len(s) > limit: s = s[:limit - 3] + "..." extra_info = pp_extra_info(obj) if extra_info != "": s += ", " + extra_info return s def fallback_findfile(filename): mods = [ m for m in sys.modules.values() if m and hasattr(m, "__file__") and filename in m.__file__ ] if len(mods) == 0: return None altfn = mods[0].__file__ if altfn[-4:-1] == ".py": altfn = altfn[:-1] # *.pyc or whatever return altfn def better_exchook(etype, value, tb, out=sys.stdout): output('Traceback (most recent call last):', out=out) allLocals,allGlobals = {},{} try: import linecache limit = None if hasattr(sys, 'tracebacklimit'): limit = sys.tracebacklimit n = 0 _tb = tb def _resolveIdentifier(namespace, id): obj = namespace[id[0]] for part in id[1:]: obj = getattr(obj, part) return obj def _trySet(old, prefix, func): if old is not None: return old try: return prefix + func() except KeyError: return old except Exception as e: return prefix + "!" + e.__class__.__name__ + ": " + str(e) while _tb is not None and (limit is None or n < limit): f = _tb.tb_frame allLocals.update(f.f_locals) allGlobals.update(f.f_globals) lineno = _tb.tb_lineno co = f.f_code filename = co.co_filename name = co.co_name output(' File "%s", line %d, in %s' % (filename,lineno,name), out=out) if not os.path.isfile(filename): altfn = fallback_findfile(filename) if altfn: output(" -- couldn't find file, trying this instead: " + altfn, out=out) filename = altfn linecache.checkcache(filename) line = linecache.getline(filename, lineno, f.f_globals) if line: line = line.strip() output(' line: ' + line, out=out) output(' locals:', out=out) alreadyPrintedLocals = set() for tokenstr in grep_full_py_identifiers(parse_py_statement(line)): splittedtoken = tuple(tokenstr.split(".")) for token in map(lambda i: splittedtoken[0:i], range(1, len(splittedtoken) + 1)): if token in alreadyPrintedLocals: continue tokenvalue = None tokenvalue = _trySet(tokenvalue, " ", lambda: pretty_print(_resolveIdentifier(f.f_locals, token))) tokenvalue = _trySet(tokenvalue, " ", lambda: pretty_print(_resolveIdentifier(f.f_globals, token))) tokenvalue = _trySet(tokenvalue, " ", lambda: pretty_print(_resolveIdentifier(f.f_builtins, token))) tokenvalue = tokenvalue or "" output(' ' + ".".join(token) + " = " + tokenvalue, out=out) alreadyPrintedLocals.add(token) if len(alreadyPrintedLocals) == 0: output(" no locals", out=out) else: output(' -- code not available --', out=out) _tb = _tb.tb_next n += 1 except Exception: output("ERROR: cannot get more detailed exception info because:", out=out) import traceback for l in traceback.format_exc().split("\n"): output(" " + l, out=out) output("simple traceback:", out=out) traceback.print_tb(tb, None, out) import types def _some_str(value): try: return str(value) except Exception: return '' % type(value).__name__ def _format_final_exc_line(etype, value): valuestr = _some_str(value) if value is None or not valuestr: line = "%s" % etype else: line = f"{etype}: {valuestr}" return line if isinstance(etype, BaseException) or etype is None or type(etype) is str: output(_format_final_exc_line(etype, value), out=out) else: output(_format_final_exc_line(etype.__name__, value), out=out) def install(): sys.excepthook = better_exchook linkchecker-10.5.0/linkcheck/bookmarks/000077500000000000000000000000001466565367000200245ustar00rootroot00000000000000linkchecker-10.5.0/linkcheck/bookmarks/__init__.py000066400000000000000000000013571466565367000221430ustar00rootroot00000000000000# Copyright (C) 2011-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. linkchecker-10.5.0/linkcheck/bookmarks/chromium.py000066400000000000000000000026301466565367000222220ustar00rootroot00000000000000# Copyright (C) 2011-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. import json def parse_bookmark_data(data): """Parse data string. Return iterator for bookmarks of the form (url, name). Bookmarks are not sorted. """ yield from parse_bookmark_json(json.loads(data)) def parse_bookmark_json(data): """Parse complete JSON data for Chromium Bookmarks.""" for entry in data["roots"].values(): yield from parse_bookmark_node(entry) def parse_bookmark_node(node): """Parse one JSON node of Chromium Bookmarks.""" if node["type"] == "url": yield node["url"], node["name"] elif node["type"] == "folder": for child in node["children"]: yield from parse_bookmark_node(child) linkchecker-10.5.0/linkcheck/bookmarks/firefox.py000066400000000000000000000032321466565367000220400ustar00rootroot00000000000000# Copyright (C) 2010-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """Parser for Firefox bookmark file.""" import re try: import sqlite3 has_sqlite = True except ImportError: has_sqlite = False extension = re.compile(r'/places.sqlite$', re.IGNORECASE) def parse_bookmark_file(filename): """Return iterator for bookmarks of the form (url, name). Bookmarks are not sorted. Returns None if sqlite3 module is not installed. """ if not has_sqlite: return conn = sqlite3.connect(filename, timeout=0.5) try: c = conn.cursor() try: sql = """SELECT mp.url, mb.title FROM moz_places mp, moz_bookmarks mb WHERE mp.hidden=0 AND mp.url NOT LIKE 'place:%' AND mp.id=mb.fk""" c.execute(sql) for url, name in c: if not name: name = url yield (url, name) finally: c.close() finally: conn.close() linkchecker-10.5.0/linkcheck/bookmarks/opera.py000066400000000000000000000023561466565367000215120ustar00rootroot00000000000000# Copyright (C) 2011-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. def parse_bookmark_data(data): """Return iterator for bookmarks of the form (url, name, line number). Bookmarks are not sorted. """ name = None lineno = 0 for line in data.splitlines(): lineno += 1 line = line.strip() if line.startswith("NAME="): name = line[5:] elif line.startswith("URL="): url = line[4:] if url and name is not None: yield (url, name, lineno) else: name = None linkchecker-10.5.0/linkcheck/bookmarks/safari.py000066400000000000000000000036151466565367000216500ustar00rootroot00000000000000# Copyright (C) 2011-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. import plistlib def parse_bookmark_data(data): """Return iterator for bookmarks of the form (url, name). Bookmarks are not sorted. """ return parse_plist(get_plist_data_from_string(data)) def get_plist_data_from_string(data): """Parse plist data for a string.""" try: return plistlib.loads(data) except Exception: # not parseable (eg. not well-formed) return {} # some key strings KEY_URLSTRING = 'URLString' KEY_URIDICTIONARY = 'URIDictionary' KEY_CHILDREN = 'Children' KEY_WEBBOOKMARKTYPE = 'WebBookmarkType' def parse_plist(entry): """Parse a XML dictionary entry.""" if is_leaf(entry): url = entry[KEY_URLSTRING] title = entry[KEY_URIDICTIONARY].get('title', url) yield (url, title) elif has_children(entry): for child in entry[KEY_CHILDREN]: yield from parse_plist(child) def is_leaf(entry): """Return true if plist entry is an URL entry.""" return entry.get(KEY_WEBBOOKMARKTYPE) == 'WebBookmarkTypeLeaf' def has_children(entry): """Return true if plist entry has children.""" return entry.get(KEY_WEBBOOKMARKTYPE) == 'WebBookmarkTypeList' linkchecker-10.5.0/linkcheck/cache/000077500000000000000000000000001466565367000170775ustar00rootroot00000000000000linkchecker-10.5.0/linkcheck/cache/__init__.py000066400000000000000000000014761466565367000212200ustar00rootroot00000000000000# Copyright (C) 2006-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Store and provide cached data during checking in a thread-safe manner. """ linkchecker-10.5.0/linkcheck/cache/results.py000066400000000000000000000044461466565367000211620ustar00rootroot00000000000000# Copyright (C) 2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Cache check results. """ from ..decorators import synchronized from ..lock import get_lock # lock object cache_lock = get_lock("results_cache_lock") class ResultCache: """ Thread-safe cache of UrlData.to_wire() results. the cache is limited in size since we rather recheck the same URL multiple times instead of running out of memory. format: {cache key (string) -> result (UrlData.towire())} """ def __init__(self, result_cache_size): """Initialize result cache.""" # mapping {URL -> cached result} self.cache = {} self.max_size = result_cache_size @synchronized(cache_lock) def get_result(self, key): """Return cached result or None if not found.""" return self.cache.get(key) @synchronized(cache_lock) def add_result(self, key, result): """Add result object to cache with given key. The request is ignored when the cache is already full or the key is None. """ if len(self.cache) > self.max_size: return if key is not None: self.cache[key] = result def has_result(self, key): """Non-thread-safe function for fast containment checks.""" return key in self.cache def has_non_empty_result(self, key): """Non-thread-safe function for fast containment checks.""" return self.cache.get(key) def __len__(self): """Get number of cached elements. This is not thread-safe and is likely to change before the returned value is used.""" return len(self.cache) linkchecker-10.5.0/linkcheck/cache/robots_txt.py000066400000000000000000000062441466565367000216660ustar00rootroot00000000000000# Copyright (C) 2006-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Cache robots.txt contents. """ import urllib.parse from .. import robotparser2 from ..containers import LFUCache from ..decorators import synchronized from ..lock import get_lock from .. import log, LOG_CACHE # lock objects cache_lock = get_lock("robots.txt_cache_lock") robot_lock = get_lock("robots.txt_robot_lock") class RobotsTxt: """ Thread-safe cache of downloaded robots.txt files. format: {cache key (string) -> robots.txt content (RobotFileParser)} """ def __init__(self, useragent): """Initialize per-URL robots.txt cache.""" # mapping {URL -> parsed robots.txt} self.cache = LFUCache(size=100) self.hits = self.misses = 0 self.roboturl_locks = {} self.useragent = useragent def allows_url(self, url_data, timeout=None): """Ask robots.txt allowance.""" roboturl = url_data.get_robots_txt_url() with self.get_lock(roboturl): return self._allows_url(url_data, roboturl, timeout) def _allows_url(self, url_data, roboturl, timeout=None): """Ask robots.txt allowance. Assumes only single thread per robots.txt URL calls this function.""" with cache_lock: if roboturl in self.cache: self.hits += 1 rp = self.cache[roboturl] return rp.can_fetch(self.useragent, url_data.url) self.misses += 1 kwargs = dict(auth=url_data.auth, session=url_data.session, timeout=timeout) rp = robotparser2.RobotFileParser(**kwargs) rp.set_url(roboturl) rp.read() with cache_lock: self.cache[roboturl] = rp self.add_sitemap_urls(rp, url_data, roboturl) return rp.can_fetch(self.useragent, url_data.url) def add_sitemap_urls(self, rp, url_data, roboturl): """Add sitemap URLs to queue.""" if not rp.sitemap_urls or not url_data.allows_simple_recursion(): return for sitemap_url, line in rp.sitemap_urls: if not urllib.parse.urlparse(sitemap_url).scheme: log.warn(LOG_CACHE, _("Relative Sitemap %s in %s discarded"), sitemap_url, roboturl) continue url_data.add_url(sitemap_url, line=line, parent=roboturl) @synchronized(robot_lock) def get_lock(self, roboturl): """Return lock for robots.txt url.""" return self.roboturl_locks.setdefault(roboturl, get_lock(roboturl)) linkchecker-10.5.0/linkcheck/cache/urlqueue.py000066400000000000000000000207141466565367000213240ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Handle a queue of URLs to check. """ import threading import collections from time import time as _time from .. import log, LOG_CACHE class Timeout(Exception): """Raised by join()""" pass class Empty(Exception): """Exception raised by get().""" pass NUM_PUTS_CLEANUP = 10000 class UrlQueue: """A queue supporting several consumer tasks. The task_done() idea is from the Python 2.5 implementation of Queue.Queue().""" def __init__(self, max_allowed_urls=None): """Initialize the queue state and task counters.""" # Note: don't put a maximum size on the queue since it would # lead to deadlocks when all worker threads called put(). self.queue = collections.deque() # mutex must be held whenever the queue is mutating. All methods # that acquire mutex must release it before returning. mutex # is shared between the two conditions, so acquiring and # releasing the conditions also acquires and releases mutex. self.mutex = threading.Lock() # Notify not_empty whenever an item is added to the queue; a # thread waiting to get is notified then. self.not_empty = threading.Condition(self.mutex) self.all_tasks_done = threading.Condition(self.mutex) self.unfinished_tasks = 0 self.finished_tasks = 0 self.in_progress = 0 self.shutdown = False # Each put() decreases the number of allowed puts. # This way we can restrict the number of URLs that are checked. if max_allowed_urls is not None and max_allowed_urls <= 0: raise ValueError( "Non-positive number of allowed URLs: %d" % max_allowed_urls ) self.max_allowed_urls = max_allowed_urls self.num_puts = 0 def qsize(self): """Return the approximate size of the queue (not reliable!).""" with self.mutex: return len(self.queue) def empty(self): """Return True if the queue is empty, False otherwise. Result is thread-safe, but not reliable since the queue could have been changed before the result is returned!""" with self.mutex: return self._empty() def _empty(self): """Return True if the queue is empty, False otherwise. Not thread-safe!""" return not self.queue def get(self, timeout=None): """Get first not-in-progress url from the queue and return it. If no such url is available return None. """ with self.not_empty: return self._get(timeout) def _get(self, timeout): """Non thread-safe utility function of self.get() doing the real work.""" if timeout is None: while self._empty(): self.not_empty.wait() else: if timeout < 0: raise ValueError("'timeout' must be a positive number") endtime = _time() + timeout while self._empty(): remaining = endtime - _time() if remaining <= 0.0: raise Empty() self.not_empty.wait(remaining) self.in_progress += 1 return self.queue.popleft() def put(self, item): """Put an item into the queue. Block if necessary until a free slot is available. """ with self.mutex: self._put(item) self.not_empty.notify() def _put(self, url_data): """Put URL in queue, increase number of unfinished tasks.""" if self.shutdown or self.max_allowed_urls == 0: return key = url_data.cache_url cache = url_data.aggregate.result_cache if cache.has_result(key): log.debug(LOG_CACHE, "skipping %s, %s already cached", url_data.url, key) return log.debug(LOG_CACHE, "queueing %s", url_data.url) if url_data.has_result: self.queue.appendleft(url_data) else: assert key is not None, "no result for None key: %s" % url_data if self.max_allowed_urls is not None: self.max_allowed_urls -= 1 self.num_puts += 1 if self.num_puts >= NUM_PUTS_CLEANUP: self.cleanup() self.queue.append(url_data) self.unfinished_tasks += 1 # add none value to cache to prevent checking this url multiple times cache.add_result(key, None) def cleanup(self): """Move cached elements to top.""" self.num_puts = 0 cached = [] for i, url_data in enumerate(self.queue): key = url_data.cache_url cache = url_data.aggregate.result_cache if cache.has_non_empty_result(key): cached.append(i) for pos in cached: self._move_to_top(pos) def _move_to_top(self, pos): """Move element at given position to top of queue.""" if pos > 0: self.queue.rotate(-pos) item = self.queue.popleft() self.queue.rotate(pos) self.queue.appendleft(item) def task_done(self, url_data): """ Indicate that a formerly enqueued task is complete. Used by Queue consumer threads. For each get() used to fetch a task, a subsequent call to task_done() tells the queue that the processing on the task is complete. If a join() is currently blocking, it will resume when all items have been processed (meaning that a task_done() call was received for every item that had been put() into the queue). Raises a ValueError if called more times than there were items placed in the queue. """ with self.all_tasks_done: log.debug(LOG_CACHE, "task_done %s", url_data.url) self.finished_tasks += 1 self.unfinished_tasks -= 1 self.in_progress -= 1 if self.unfinished_tasks <= 0: if self.unfinished_tasks < 0: raise ValueError('task_done() called too many times') self.all_tasks_done.notify_all() def join(self, timeout=None): """Blocks until all items in the Queue have been gotten and processed. The count of unfinished tasks goes up whenever an item is added to the queue. The count goes down whenever a consumer thread calls task_done() to indicate the item was retrieved and all work on it is complete. When the count of unfinished tasks drops to zero, join() unblocks. """ with self.all_tasks_done: if timeout is None: while self.unfinished_tasks: self.all_tasks_done.wait() else: if timeout < 0: raise ValueError("'timeout' must be a positive number") endtime = _time() + timeout while self.unfinished_tasks: remaining = endtime - _time() if remaining <= 0.0: raise Timeout() self.all_tasks_done.wait(remaining) def do_shutdown(self): """Shutdown the queue by not accepting any more URLs.""" with self.mutex: unfinished = self.unfinished_tasks - len(self.queue) self.queue.clear() if unfinished <= 0: if unfinished < 0: raise ValueError('shutdown is in error') self.all_tasks_done.notify_all() self.unfinished_tasks = unfinished self.shutdown = True def status(self): """Get tuple (finished tasks, in progress, queue size).""" # no need to acquire self.mutex since the numbers are unreliable anyways. return (self.finished_tasks, self.in_progress, len(self.queue)) linkchecker-10.5.0/linkcheck/checker/000077500000000000000000000000001466565367000174405ustar00rootroot00000000000000linkchecker-10.5.0/linkcheck/checker/__init__.py000066400000000000000000000143051466565367000215540ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Main functions for link checking. """ import os import html import urllib.parse from .. import url as urlutil, log, LOG_CHECK MAX_FILESIZE = 1024 * 1024 * 10 # 10MB def guess_url(url): """Guess if URL is a http or ftp URL. @param url: the URL to check @type url: unicode @return: url with *http://* or *ftp://* prepended if it's detected as a http respective ftp URL. @rtype: unicode """ if url.lower().endswith(".html") and "/" not in url: return url if url.lower().startswith("www."): # syntactic sugar return f"http://{url}" elif url.lower().startswith("ftp."): # syntactic sugar return f"ftp://{url}" return url def absolute_url(base_url, base_ref, parent_url): """ Search for the absolute url to detect the link type. This does not join any url fragments together! @param base_url: base url from a link tag @type base_url: string or None @param base_ref: base url from tag @type base_ref: string or None @param parent_url: url of parent document @type parent_url: string or None """ if base_url and urlutil.url_is_absolute(base_url): return base_url elif base_ref and urlutil.url_is_absolute(base_ref): return base_ref elif parent_url and urlutil.url_is_absolute(parent_url): return parent_url return "" def get_url_from( base_url, recursion_level, aggregate, parent_url=None, base_ref=None, line=None, column=None, page=0, name="", parent_content_type=None, extern=None, url_encoding=None, ): """ Get url data from given base data. @param base_url: base url from a link tag @type base_url: string or None @param recursion_level: current recursion level @type recursion_level: number @param aggregate: aggregate object @type aggregate: aggregate.Consumer @param parent_url: parent url @type parent_url: string or None @param base_ref: base url from tag @type base_ref: string or None @param line: line number @type line: number @param column: column number @type column: number @param page: page number @type page: number @param name: link name @type name: string @param extern: (is_extern, is_strict) or None @type extern: tuple(int, int) or None """ if base_url is not None: # left strip for detection of URL scheme base_url_stripped = base_url.lstrip() else: base_url_stripped = base_url url = absolute_url(base_url_stripped, base_ref, parent_url).lower() if ":" in url: scheme = url.split(":", 1)[0].lower() else: scheme = None if not (url or name): # use filename as base url, with slash as path separator name = base_url.replace("\\", "/") allowed_schemes = aggregate.config["allowedschemes"] # ignore local PHP files with execution directives local_php = ( parent_content_type == 'application/x-httpd-php' and '' in base_url and scheme == 'file' ) if local_php or (allowed_schemes and scheme not in allowed_schemes): klass = ignoreurl.IgnoreUrl else: assume_local_file = recursion_level == 0 klass = get_urlclass_from(scheme, assume_local_file=assume_local_file) if "AnchorCheck" in aggregate.config["enabledplugins"] and \ klass == fileurl.FileUrl: klass = fileurl.AnchorCheckFileUrl log.debug(LOG_CHECK, "%s handles url %s", klass.__name__, base_url) return klass( base_url, recursion_level, aggregate, parent_url=parent_url, base_ref=base_ref, line=line, column=column, page=page, name=name, extern=extern, url_encoding=url_encoding, ) def get_urlclass_from(scheme, assume_local_file=False): """Return checker class for given URL scheme. If the scheme cannot be matched and assume_local_file is True, assume a local file. """ if scheme in ("http", "https"): klass = httpurl.HttpUrl elif scheme == "ftp": klass = ftpurl.FtpUrl elif scheme == "file": klass = fileurl.FileUrl elif scheme == "mailto": klass = mailtourl.MailtoUrl elif scheme == "dns": klass = dnsurl.DnsUrl elif scheme == "itms-services": klass = itmsservicesurl.ItmsServicesUrl elif scheme and unknownurl.is_unknown_scheme(scheme): klass = unknownurl.UnknownUrl elif assume_local_file: klass = fileurl.FileUrl else: klass = unknownurl.UnknownUrl return klass def get_index_html(urls): """ Construct artificial index.html from given URLs. @param urls: URL strings @type urls: iterator of string """ lines = ["", ""] for entry in urls: name = html.escape(entry) try: url = html.escape(urllib.parse.quote(entry)) except UnicodeEncodeError: log.warn(LOG_CHECK, "Unable to convert entry to Unicode") continue except KeyError: # Some unicode entries raise KeyError. url = name lines.append(f'{name}') lines.extend(["", ""]) return os.linesep.join(lines).encode() # all the URL classes from . import ( # noqa: E402 fileurl, unknownurl, ftpurl, httpurl, dnsurl, mailtourl, ignoreurl, itmsservicesurl, ) linkchecker-10.5.0/linkcheck/checker/const.py000066400000000000000000000104611466565367000211420ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Helper constants. """ import socket import ftplib import requests from .. import LinkCheckerError from dns.exception import DNSException # Catch these exception on syntax checks. ExcSyntaxList = [ LinkCheckerError, ValueError, ] # Catch these exceptions on content and connect checks. All other # exceptions are internal or system errors ExcCacheList = [ IOError, OSError, # OSError is thrown on Windows when a file is not found LinkCheckerError, DNSException, EOFError, # http errors requests.exceptions.RequestException, requests.packages.urllib3.exceptions.HTTPError, # pylint: disable=no-member # ftp errors ftplib.Error, # idna.encode(), called from socket.create_connection() UnicodeError, ] # Exceptions that do not put the URL in the cache so that the URL can # be checked again. ExcNoCacheList = [ socket.timeout, ] # firefox bookmark file needs sqlite3 for parsing try: import sqlite3 ExcCacheList.append(sqlite3.Error) except ImportError: pass # pyOpenSSL errors try: import OpenSSL ExcCacheList.append(OpenSSL.SSL.Error) except ImportError: pass ExcList = ExcCacheList + ExcNoCacheList # Maximum URL length # https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers URL_MAX_LENGTH = 2047 # the warnings WARN_URL_EFFECTIVE_URL = "url-effective-url" WARN_URL_ERROR_GETTING_CONTENT = "url-error-getting-content" WARN_URL_CONTENT_SIZE_TOO_LARGE = "url-content-too-large" WARN_URL_CONTENT_SIZE_ZERO = "url-content-size-zero" WARN_URL_CONTENT_TYPE_UNPARSEABLE = "url-content-type-unparseable" WARN_URL_OBFUSCATED_IP = "url-obfuscated-ip" WARN_URL_TOO_LONG = "url-too-long" WARN_URL_WHITESPACE = "url-whitespace" WARN_FILE_MISSING_SLASH = "file-missing-slash" WARN_FILE_SYSTEM_PATH = "file-system-path" WARN_FILE_ANCHORCHECK_DIRECTORY = "file-anchorcheck-directory" WARN_FTP_MISSING_SLASH = "ftp-missing-slash" WARN_HTTP_EMPTY_CONTENT = "http-empty-content" WARN_HTTP_COOKIE_STORE_ERROR = "http-cookie-store-error" WARN_HTTP_RATE_LIMITED = "http-rate-limited" WARN_HTTP_REDIRECTED = "http-redirected" WARN_MAIL_NO_MX_HOST = "mail-no-mx-host" WARN_XML_PARSE_ERROR = "xml-parse-error" # registered warnings Warnings = { WARN_URL_EFFECTIVE_URL: _("The effective URL is different from the original."), WARN_URL_ERROR_GETTING_CONTENT: _("Could not get the content of the URL."), WARN_URL_CONTENT_SIZE_TOO_LARGE: _("The URL content size is too large."), WARN_URL_CONTENT_SIZE_ZERO: _("The URL content size is zero."), WARN_URL_CONTENT_TYPE_UNPARSEABLE: _("The URL content type is not parseable."), WARN_URL_TOO_LONG: _("The URL is longer than the recommended size."), WARN_URL_WHITESPACE: _("The URL contains leading or trailing whitespace."), WARN_FILE_MISSING_SLASH: _("The file: URL is missing a trailing slash."), WARN_FILE_SYSTEM_PATH: _( "The file: path is not the same as the system specific path." ), WARN_FILE_ANCHORCHECK_DIRECTORY: _( "A local directory with an anchor, not supported by AnchorCheck."), WARN_FTP_MISSING_SLASH: _("The ftp: URL is missing a trailing slash."), WARN_HTTP_EMPTY_CONTENT: _("The URL had no content."), WARN_HTTP_COOKIE_STORE_ERROR: _("An error occurred while storing a cookie."), WARN_HTTP_RATE_LIMITED: _("The URL request was rate limited."), WARN_HTTP_REDIRECTED: _("Redirected to a different URL."), WARN_MAIL_NO_MX_HOST: _("The mail MX host could not be found."), WARN_URL_OBFUSCATED_IP: _("The IP is obfuscated."), WARN_XML_PARSE_ERROR: _("XML could not be parsed."), } linkchecker-10.5.0/linkcheck/checker/dnsurl.py000066400000000000000000000027641466565367000213320ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Handler for dns: links. """ import socket from . import urlbase class DnsUrl(urlbase.UrlBase): """ Url link with dns scheme. """ def can_get_content(self): """ dns: URLs do not have any content @return: False @rtype: bool """ return False def check_connection(self): """Resolve hostname.""" host = self.urlparts[1] addresses = socket.getaddrinfo(host, 80, 0, 0, socket.SOL_TCP) args = {'host': host} if addresses: args['ips'] = [x[4][0] for x in addresses] self.set_result(_('%(host)s resolved to IPs %(ips)s') % args, valid=True) else: self.set_result(_('%(host)r could not be resolved') % args, valid=False) linkchecker-10.5.0/linkcheck/checker/fileurl.py000066400000000000000000000322361466565367000214620ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Handle local file: links. """ import re import os import urllib.parse import urllib.request from datetime import datetime, timezone from . import urlbase, get_index_html from .. import log, LOG_CHECK, fileutil, mimeutil, LinkCheckerError, url as urlutil from ..bookmarks import firefox from .const import (WARN_FILE_MISSING_SLASH, WARN_FILE_SYSTEM_PATH, WARN_FILE_ANCHORCHECK_DIRECTORY) def get_files(dirname): """Get iterator of entries in directory. Only allows regular files and directories, no symlinks.""" for entry in os.listdir(dirname): fullentry = os.path.join(dirname, entry) if os.path.islink(fullentry): continue if os.path.isfile(fullentry): yield entry elif os.path.isdir(fullentry): yield entry + "/" def prepare_urlpath_for_nt(path): """ URLs like *file://server/path/* result in a path named */server/path*. However urllib.url2pathname expects *////server/path*. """ if '|' not in path: return "////" + path.lstrip("/") return path def get_nt_filename(path): """Return case sensitive filename for NT path.""" unc, rest = os.path.splitdrive(path) head, tail = os.path.split(rest) if not tail: return path for fname in os.listdir(unc + head): if fname.lower() == tail.lower(): return os.path.join(get_nt_filename(unc + head), fname) log.error(LOG_CHECK, "could not find %r in %r", tail, head) return path def get_os_filename(path): """Return filesystem path for given URL path.""" if os.name == 'nt': path = prepare_urlpath_for_nt(path) res = urllib.request.url2pathname(fileutil.path_safe(path)) if os.name == 'nt' and res.endswith(':') and len(res) == 2: # Work around https://bugs.python.org/issue11474 res += os.sep return res def is_absolute_path(path): """Check if given path is absolute. On Windows absolute paths start with a drive letter. On all other systems absolute paths start with a slash.""" if os.name == 'nt': if re.search(r"^[a-zA-Z]:", path): return True path = path.replace("\\", "/") return path.startswith("/") class FileUrl(urlbase.UrlBase): """ Url link with file scheme. """ def init( self, base_ref, base_url, parent_url, recursion_level, aggregate, line, column, page, name, url_encoding, extern, ): """Initialize the scheme.""" super().init( base_ref, base_url, parent_url, recursion_level, aggregate, line, column, page, name, url_encoding, extern, ) self.scheme = 'file' def build_base_url(self): """The URL is normed according to the platform: - the base URL is made an absolute *file://* URL - under Windows platform the drive specifier is normed """ if self.base_url is None: return base_url = self.base_url if not (self.parent_url or self.base_ref or base_url.startswith("file:")): base_url = os.path.expanduser(base_url) if not is_absolute_path(base_url): try: base_url = os.getcwd() + "/" + base_url except OSError as msg: # occurs on stale remote filesystems (eg. NFS) errmsg = _( "Could not get current working directory: %(msg)s" ) % dict(msg=msg) raise LinkCheckerError(errmsg) if os.path.isdir(base_url): base_url += "/" base_url = "file://" + base_url if os.name == "nt": base_url = base_url.replace("\\", "/") # transform c:/windows into /c|/windows base_url = re.sub("^file://(/?)([a-zA-Z]):", r"file:///\2|", base_url) # transform file://path into file:///path base_url = re.sub("^file://([^/])", r"file:///\1", base_url) self.base_url = base_url def build_url(self): """ Calls super.build_url() and adds a trailing slash to directories. """ self.build_base_url() if self.parent_url is not None: # URL joining with the parent URL only works if the query # of the base URL are removed first. # Otherwise the join function thinks the query is part of # the file name. urlparts = list(urllib.parse.urlsplit(self.base_url)) # ignore query part for filesystem urls urlparts[3] = '' self.base_url = urlutil.urlunsplit(urlparts) super().build_url() # ignore query and fragment url parts for filesystem urls self.urlparts[3] = self.urlparts[4] = '' if self.is_directory() and not self.urlparts[2].endswith('/'): self.add_warning( _("Added trailing slash to directory."), tag=WARN_FILE_MISSING_SLASH ) self.urlparts[2] += '/' self.url = urlutil.urlunsplit(self.urlparts) def add_size_info(self): """Get size of file content and modification time from filename path.""" if self.is_directory(): # Directory size always differs from the customer index.html # that is generated. So return without calculating any size. return filename = self.get_os_filename() self.size = fileutil.get_size(filename) self.modified = datetime.fromtimestamp( fileutil.get_mtime(filename), tz=timezone.utc) def check_connection(self): """ Try to open the local file. Under NT systems the case sensitivity is checked. """ if self.parent_url is not None and not self.parent_url.startswith("file:"): msg = _( "local files are only checked without parent URL or when" " the parent URL is also a file" ) raise LinkCheckerError(msg) if self.is_directory(): self.set_result(_("directory")) else: url = fileutil.path_safe(self.url) self.url_connection = urllib.request.urlopen(url) self.check_case_sensitivity() def check_case_sensitivity(self): """ Check if url and windows path name match cases else there might be problems when copying such files on web servers that are case sensitive. """ if os.name != 'nt': return path = self.get_os_filename() realpath = get_nt_filename(path) if path != realpath: self.add_warning( _( "The URL path %(path)r is not the same as the" " system path %(realpath)r. You should always use" " the system path in URLs." ) % {"path": path, "realpath": realpath}, tag=WARN_FILE_SYSTEM_PATH, ) def read_content(self): """Return file content, or in case of directories a dummy HTML file with links to the files.""" if self.is_directory(): data = get_index_html(get_files(self.get_os_filename())) else: data = super().read_content() return data def get_os_filename(self): """ Construct os specific file path out of the *file://* URL. @return: file name @rtype: string """ return get_os_filename(self.urlparts[2]) def get_temp_filename(self): """Get filename for content to parse.""" return self.get_os_filename() def is_directory(self): """ Check if file is a directory. @return: True iff file is a directory @rtype: bool """ filename = self.get_os_filename() return os.path.isdir(filename) and not os.path.islink(filename) def is_parseable(self): """Check if content is parseable for recursion. @return: True if content is parseable @rtype: bool """ if self.is_directory(): return True if firefox.has_sqlite and firefox.extension.search(self.url): return True return self.is_content_type_parseable() def set_content_type(self): """Set URL content type, or an empty string if content type could not be found.""" if self.url: self.content_type = mimeutil.guess_mimetype(self.url, read=self.get_content) else: self.content_type = "" log.debug(LOG_CHECK, "MIME type: %s", self.content_type) def get_intern_pattern(self, url=None): """Get pattern for intern URL matching. @return non-empty regex pattern or None @rtype String or None """ if url is None: url = self.url if not url: return None if url.startswith('file://'): i = url.rindex('/') if i > 6: # remove last filename to make directory internal url = url[: i + 1] return re.escape(url) def add_url(self, url, line=0, column=0, page=0, name="", base=None): """If a local webroot directory is configured, replace absolute URLs with it. After that queue the URL data for checking.""" webroot = self.aggregate.config["localwebroot"] if webroot and url and url.startswith("/"): url = webroot + url[1:] log.debug(LOG_CHECK, "Applied local webroot `%s' to `%s'.", webroot, url) super().add_url(url, line=line, column=column, page=page, name=name, base=base) class AnchorCheckFileUrl(FileUrl): """ File URL link for AnchorCheck plugin. """ def reset(self): super().reset() # the local file URI self.url_without_anchor = None def build_url(self): """ Calls UrlBase.build_url() and adds a trailing slash to directories. """ self.build_base_url() if self.parent_url is not None: # URL joining with the parent URL only works if the query # of the base URL are removed first. # Otherwise the join function thinks the query is part of # the file name. urlparts = list(urllib.parse.urlsplit(self.base_url)) # ignore query part for filesystem urls urlparts[3] = '' self.base_url = urlutil.urlunsplit(urlparts) super(FileUrl, self).build_url() # ignore query url part for filesystem urls self.urlparts[3] = '' if self.is_directory() and not self.urlparts[2].endswith('/'): self.add_warning( _("Added trailing slash to directory."), tag=WARN_FILE_MISSING_SLASH ) self.urlparts[2] += '/' self.url = urlutil.urlunsplit(self.urlparts) self.url_without_anchor = urlutil.urlunsplit(self.urlparts[:4] + ['']) def check_connection(self): """ Try to open the local file. Under NT systems the case sensitivity is checked. """ if self.parent_url is not None and not self.parent_url.startswith("file:"): msg = _( "local files are only checked without parent URL or when" " the parent URL is also a file" ) raise LinkCheckerError(msg) if self.is_directory(): if self.anchor: self.add_warning( _( "URL `%s' is a directory with an anchor." " When checking local files AnchorCheck does not support" " anchors for directories." ) % self.url, tag=WARN_FILE_ANCHORCHECK_DIRECTORY, ) self.set_result(_("directory")) else: url = fileutil.path_safe(self.url_without_anchor) self.url_connection = urllib.request.urlopen(url) self.check_case_sensitivity() def set_content_type(self): """Set URL content type, or an empty string if content type could not be found.""" if self.url: self.content_type = mimeutil.guess_mimetype( self.url_without_anchor, read=self.get_content) else: self.content_type = "" log.debug(LOG_CHECK, "MIME type: %s", self.content_type) linkchecker-10.5.0/linkcheck/checker/ftpurl.py000066400000000000000000000157401466565367000213350ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Handle FTP links. """ import ftplib from io import BytesIO from .. import log, LOG_CHECK, LinkCheckerError, mimeutil from . import internpaturl, get_index_html from .const import WARN_FTP_MISSING_SLASH class FtpUrl(internpaturl.InternPatternUrl): """ Url link with ftp scheme. """ def reset(self): """ Initialize FTP url data. """ super().reset() # list of files for recursion self.files = [] # last part of URL filename self.filename = None self.filename_encoding = 'iso-8859-1' def check_connection(self): """ Check in this order: login, changing directory, list the file. """ self.login() self.negotiate_encoding() self.filename = self.cwd() self.listfile() self.files = [] return None def login(self): """Log into ftp server and check the welcome message.""" self.url_connection = ftplib.FTP(timeout=self.aggregate.config["timeout"]) if log.is_debug(LOG_CHECK): self.url_connection.set_debuglevel(1) try: self.url_connection.connect(self.host, self.port) _user, _password = self.get_user_password() if _user is None: self.url_connection.login() elif _password is None: self.url_connection.login(_user) else: self.url_connection.login(_user, _password) info = self.url_connection.getwelcome() if info: # note that the info may change every time a user logs in, # so don't add it to the url_data info. log.debug(LOG_CHECK, "FTP info %s", info) else: raise LinkCheckerError(_("Got no answer from FTP server")) except EOFError as msg: raise LinkCheckerError( _("Remote host has closed connection: %(msg)s") % str(msg) ) def negotiate_encoding(self): """Check if server can handle UTF-8 encoded filenames. See also RFC 2640.""" try: features = self.url_connection.sendcmd("FEAT") except ftplib.error_perm as msg: log.debug(LOG_CHECK, "Ignoring error when getting FTP features: %s" % msg) else: log.debug(LOG_CHECK, "FTP features %s", features) if " UTF-8" in features.splitlines(): self.filename_encoding = "utf-8" def cwd(self): """ Change to URL parent directory. Return filename of last path component. """ path = self.urlparts[2] if isinstance(path, bytes): path = path.decode(self.filename_encoding, 'replace') dirname = path.strip('/') dirs = dirname.split('/') filename = dirs.pop() self.url_connection.cwd('/') for d in dirs: self.url_connection.cwd(d) return filename def listfile(self): """ See if filename is in the current FTP directory. """ if not self.filename: return files = self.get_files() log.debug(LOG_CHECK, "FTP files %s", str(files)) if self.filename in files: # file found return # it could be a directory if the trailing slash was forgotten if f"{self.filename}/" in files: if not self.url.endswith('/'): self.add_warning( _("Missing trailing directory slash in ftp url."), tag=WARN_FTP_MISSING_SLASH, ) self.url += '/' return raise ftplib.error_perm("550 File not found") def get_files(self): """Get list of filenames in directory. Subdirectories have an ending slash.""" files = [] def add_entry(line): """Parse list line and add the entry it points to to the file list.""" log.debug(LOG_CHECK, "Directory entry %r", line) from ..ftpparse import ftpparse fpo = ftpparse(line) if fpo is not None and fpo["name"]: name = fpo["name"] if fpo["trycwd"]: name += "/" if fpo["trycwd"] or fpo["tryretr"]: files.append(name) self.url_connection.dir(add_entry) return files def is_parseable(self): """See if URL target is parseable for recursion.""" if self.is_directory(): return True return self.is_content_type_parseable() def is_directory(self): """See if URL target is a directory.""" # either the path is empty, or ends with a slash path = self.urlparts[2] return (not path) or path.endswith('/') def set_content_type(self): """Set URL content type, or an empty string if content type could not be found.""" self.content_type = mimeutil.guess_mimetype(self.url, read=self.get_content) log.debug(LOG_CHECK, "MIME type: %s", self.content_type) def read_content(self): """Return URL target content, or in case of directories a dummy HTML file with links to the files.""" if self.is_directory(): self.url_connection.cwd(self.filename) self.files = self.get_files() # XXX limit number of files? data = get_index_html(self.files) else: # download file in BINARY mode ftpcmd = f"RETR {self.filename}" buf = BytesIO() def stor_data(s): """Helper method storing given data""" # limit the download size if (buf.tell() + len(s)) > self.aggregate.config["maxfilesizedownload"]: raise LinkCheckerError(_("FTP file size too large")) buf.write(s) self.url_connection.retrbinary(ftpcmd, stor_data) data = buf.getvalue() buf.close() return data def close_connection(self): """Release the open connection from the connection pool.""" if self.url_connection is not None: try: self.url_connection.quit() except Exception: pass self.url_connection = None linkchecker-10.5.0/linkcheck/checker/httpurl.py000066400000000000000000000352771466565367000215320ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Handle http links. """ import requests # The validity of SSL certs is ignored to be able # the check the URL and recurse into it. # The warning about invalid SSL certs is given to the # user instead. import warnings warnings.simplefilter( # pylint: disable=no-member 'ignore', requests.packages.urllib3.exceptions.InsecureRequestWarning ) from io import BytesIO import re from .. import ( log, LOG_CHECK, mimeutil, url as urlutil, LinkCheckerError, httputil, ) from . import internpaturl # import warnings from .const import WARN_HTTP_EMPTY_CONTENT, WARN_HTTP_RATE_LIMITED, WARN_HTTP_REDIRECTED from requests.sessions import REDIRECT_STATI HTTP_SCHEMAS = ('http://', 'https://') # match for robots meta element content attribute nofollow_re = re.compile(r"\bnofollow\b", re.IGNORECASE) class HttpUrl(internpaturl.InternPatternUrl): """ Url link with http scheme. """ def reset(self): """ Initialize HTTP specific variables. """ super().reset() # initialize check data # server headers self.headers = {} self.auth = None self.ssl_cipher = None self.ssl_cert = None def allows_robots(self, url): """ Fetch and parse the robots.txt of given url. Checks if LinkChecker can get the requested resource content. @param url: the url to be requested @type url: string @return: True if access is granted, otherwise False @rtype: bool """ return not self.aggregate.config[ 'robotstxt' ] or self.aggregate.robots_txt.allows_url( self, timeout=self.aggregate.config["timeout"] ) def content_allows_robots(self): """ Return False if the content of this URL forbids robots to search for recursive links. """ if not self.is_html(): return True soup = self.get_soup() return not soup.find("meta", attrs={"name": "robots", "content": nofollow_re}) def add_size_info(self): """Get size of URL content from HTTP header.""" if ( self.headers and "Content-Length" in self.headers and "Transfer-Encoding" not in self.headers ): # Note that content-encoding causes size differences since # the content data is always decoded. try: self.size = int(self.headers["Content-Length"]) except (ValueError, OverflowError): pass else: self.size = -1 def check_connection(self): """ Check a URL with HTTP protocol. Here is an excerpt from RFC 1945 with common response codes: The first digit of the Status-Code defines the class of response. The last two digits do not have any categorization role. There are 5 values for the first digit: - 1xx: Informational - Not used, but reserved for future use - 2xx: Success - The action was successfully received, understood, and accepted - 3xx: Redirection - Further action must be taken in order to complete the request - 4xx: Client Error - The request contains bad syntax or cannot be fulfilled - 5xx: Server Error - The server failed to fulfill an apparently valid request """ self.session = self.aggregate.get_request_session() self.construct_auth() # check robots.txt if not self.allows_robots(self.url): self.add_info(_("Access denied by robots.txt, checked only syntax.")) self.set_result(_("syntax OK")) self.do_check_content = False return # check the http connection request = self.build_request() self.send_request(request) self._add_response_info() self.follow_redirections(request) self.check_response() if self.allows_simple_recursion(): self.parse_header_links() def build_request(self): """Build a prepared request object.""" clientheaders = {} if self.parent_url and self.parent_url.lower().startswith(HTTP_SCHEMAS): clientheaders["Referer"] = self.parent_url kwargs = dict(method='GET', url=self.url, headers=clientheaders) if self.auth: kwargs['auth'] = self.auth log.debug(LOG_CHECK, "Prepare request with %s", kwargs) request = requests.Request(**kwargs) return self.session.prepare_request(request) def send_request(self, request): """Send request and store response in self.url_connection.""" # throttle the number of requests to each host self.aggregate.wait_for_host(self.urlparts[1]) kwargs = self.get_request_kwargs() kwargs["allow_redirects"] = False self._send_request(request, **kwargs) def _send_request(self, request, **kwargs): """Send GET request.""" log.debug(LOG_CHECK, "Send request %s with %s", request, kwargs) log.debug(LOG_CHECK, "Request headers %s", request.headers) self.url_connection = self.session.send(request, **kwargs) self.headers = self.url_connection.headers log.debug(LOG_CHECK, "Response headers %s", self.headers) self.set_encoding(self.url_connection.encoding) log.debug(LOG_CHECK, "Response encoding %s", self.content_encoding) if "LinkChecker" in self.headers: self.aggregate.set_maxrated_for_host(self.urlparts[1]) self._add_ssl_info() def _add_response_info(self): """Set info from established HTTP(S) connection.""" self.set_content_type() self.add_size_info() def _get_ssl_sock(self): """Get raw SSL socket.""" assert self.scheme == "https", self raw_connection = self.url_connection.raw._connection if not raw_connection: # this happens with newer requests versions: # https://github.com/linkchecker/linkchecker/issues/76 return None if raw_connection.sock is None: # sometimes the socket is not yet connected # see https://github.com/psf/requests/issues/1966 raw_connection.connect() return raw_connection.sock def _add_ssl_info(self): """Add SSL cipher info.""" if self.scheme == 'https': sock = self._get_ssl_sock() if not sock: log.debug(LOG_CHECK, "cannot extract SSL certificate from connection") self.ssl_cert = None elif hasattr(sock, 'cipher'): self.ssl_cert = sock.getpeercert() else: # using pyopenssl cert = sock.connection.get_peer_certificate() self.ssl_cert = httputil.x509_to_dict(cert) log.debug(LOG_CHECK, "Got SSL certificate %s", self.ssl_cert) else: self.ssl_cert = None def construct_auth(self): """Construct HTTP Basic authentication credentials if there is user/password information available. Does not overwrite if credentials have already been constructed.""" if self.auth: return _user, _password = self.get_user_password() if _user is not None and _password is not None: self.auth = (_user, _password) def set_content_type(self): """Set MIME type from HTTP response headers.""" self.content_type = httputil.get_content_type(self.headers) log.debug(LOG_CHECK, "MIME type: %s", self.content_type) def set_encoding(self, encoding): """Set content encoding""" if encoding == "ISO-8859-1": # Although RFC 2616 (HTTP/1.1) says that text data in a non-ISO-8859-1 # (or subset) character set must be labelled with a charset, # that is not always the case and then the default ISO-8859-1 is # set by Requests. # We fall back to it in UrlBase.get_content() if Beautiful Soup # doesn't return an encoding. self.content_encoding = None else: self.content_encoding = encoding def is_redirect(self): """Check if current response is a redirect.""" return ( 'location' in self.headers and self.url_connection.status_code in REDIRECT_STATI ) def get_request_kwargs(self): """Construct keyword parameters for Session.request() and Session.resolve_redirects().""" kwargs = dict(stream=True, timeout=self.aggregate.config["timeout"]) if self.scheme == "https" and self.aggregate.config["sslverify"]: kwargs['verify'] = self.aggregate.config["sslverify"] else: kwargs['verify'] = False return kwargs def get_redirects(self, request): """Return iterator of redirects for given request.""" kwargs = self.get_request_kwargs() return self.session.resolve_redirects(self.url_connection, request, **kwargs) def follow_redirections(self, request): """Follow all redirections of http response.""" log.debug(LOG_CHECK, "follow all redirections") if self.is_redirect(): # run connection plugins for old connection self.aggregate.plugin_manager.run_connection_plugins(self) response = None for response in self.get_redirects(request): newurl = response.url log.debug(LOG_CHECK, "Redirected to %r", newurl) self.aliases.append(newurl) # XXX on redirect errors this is not printed self.add_warning( _("Redirected to `%(url)s' status: %(code)d %(reason)s.") % {'url': newurl, 'code': self.url_connection.status_code, 'reason': self.url_connection.reason}, tag=WARN_HTTP_REDIRECTED) # Reset extern and recalculate self.extern = None self.set_extern(newurl) self.urlparts = self.build_url_parts(newurl) self.url_connection = response self.headers = response.headers self.url = urlutil.urlunsplit(self.urlparts) self.scheme = self.urlparts[0].lower() self._add_ssl_info() self._add_response_info() if self.is_redirect(): # run connection plugins for old connection self.aggregate.plugin_manager.run_connection_plugins(self) if response: log.debug(LOG_CHECK, "Redirected response headers %s", response.headers) self.set_encoding(response.encoding) log.debug( LOG_CHECK, "Redirected response encoding %s", self.content_encoding) def check_response(self): """Check final result and log it.""" if ( self.url_connection.status_code >= 400 and self.url_connection.status_code != 429 ): self.set_result( "%d %s" % (self.url_connection.status_code, self.url_connection.reason), valid=False, ) else: if self.url_connection.status_code == 204: # no content self.add_warning( self.url_connection.reason, tag=WARN_HTTP_EMPTY_CONTENT ) if self.url_connection.status_code == 429: self.add_warning( "Rate limited (Retry-After: %s)" % self.headers.get("Retry-After"), tag=WARN_HTTP_RATE_LIMITED, ) if self.url_connection.status_code >= 200: self.set_result( "%r %s" % (self.url_connection.status_code, self.url_connection.reason) ) else: self.set_result(_("OK")) def get_content(self): return super().get_content(self.content_encoding) def read_content(self): """Return data and data size for this URL. Can be overridden in subclasses.""" maxbytes = self.aggregate.config["maxfilesizedownload"] buf = BytesIO() for data in self.url_connection.iter_content(chunk_size=self.ReadChunkBytes): if buf.tell() + len(data) > maxbytes: raise LinkCheckerError(_("File size too large")) buf.write(data) return buf.getvalue() def parse_header_links(self): """Parse URLs in HTTP headers Link:.""" for linktype, linkinfo in self.url_connection.links.items(): url = linkinfo["url"] name = f"Link: header {linktype}" self.add_url(url, name=name) if 'Refresh' in self.headers: from ..htmlutil.linkparse import refresh_re value = self.headers['Refresh'].strip() mo = refresh_re.match(value) if mo: url = mo.group("url") name = "Refresh: header" self.add_url(url, name=name) if 'Content-Location' in self.headers: url = self.headers['Content-Location'].strip() name = "Content-Location: header" self.add_url(url, name=name) def is_parseable(self): """ Check if content is parseable for recursion. @return: True if content is parseable @rtype: bool """ if not self.valid: return False # some content types must be validated with the page content if self.content_type in ("application/xml", "text/xml"): rtype = mimeutil.guess_mimetype_read(self.get_content) if rtype is not None: # XXX side effect self.content_type = rtype log.debug(LOG_CHECK, "Read MIME type: %s", self.content_type) return self.is_content_type_parseable() def get_robots_txt_url(self): """ Get the according robots.txt URL for this URL. @return: robots.txt URL @rtype: string """ return "%s://%s/robots.txt" % tuple(self.urlparts[0:2]) linkchecker-10.5.0/linkcheck/checker/ignoreurl.py000066400000000000000000000017261466565367000220260ustar00rootroot00000000000000# Copyright (C) 2012-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Handle ignored URLs. """ from . import unknownurl class IgnoreUrl(unknownurl.UnknownUrl): """Always ignored URL.""" def is_ignored(self): """Return True if this URL scheme is ignored.""" return True linkchecker-10.5.0/linkcheck/checker/internpaturl.py000066400000000000000000000042361466565367000225460ustar00rootroot00000000000000# Copyright (C) 2005-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Intern URL pattern support. """ import re import urllib.parse from . import urlbase, absolute_url from .. import url as urlutil def get_intern_pattern(url): """Return intern pattern for given URL. Redirections to the same domain with or without "www." prepended are allowed.""" parts = urllib.parse.urlsplit(url) scheme = parts[0].lower() domain = parts[1].lower() domain, is_idn = urlutil.idna_encode(domain) # allow redirection www.example.com -> example.com and vice versa if domain.startswith('www.'): domain = domain[4:] if not (domain and scheme): return None path = urlutil.splitparams(parts[2])[0] segments = path.split('/')[:-1] path = "/".join(segments) if url.endswith('/'): path += '/' args = list(re.escape(x) for x in (scheme, domain, path)) if args[0] in ('http', 'https'): args[0] = 'https?' args[1] = r"(www\.|)%s" % args[1] return "^%s://%s%s" % tuple(args) class InternPatternUrl(urlbase.UrlBase): """Class supporting an intern URL pattern.""" def get_intern_pattern(self, url=None): """ Get pattern for intern URL matching. @return non-empty regex pattern or None @rtype String or None """ if url is None: url = absolute_url(self.base_url, self.base_ref, self.parent_url) if not url: return None return get_intern_pattern(url) linkchecker-10.5.0/linkcheck/checker/itmsservicesurl.py000066400000000000000000000026701466565367000232620ustar00rootroot00000000000000# Copyright (C) 2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Handle itms-services URLs. """ from . import urlbase from .. import log, LOG_CHECK class ItmsServicesUrl(urlbase.UrlBase): """Apple iOS application download URLs.""" def check_syntax(self): """Only logs that this URL is unknown.""" super().check_syntax() if "url=" not in self.urlparts[3]: self.set_result(_("Missing required url parameter"), valid=False) def local_check(self): """Disable content checks.""" log.debug(LOG_CHECK, "Checking %s", self) def check_content(self): """Allow recursion to check the url CGI param.""" return True def is_parseable(self): """This URL is parseable.""" return True linkchecker-10.5.0/linkcheck/checker/mailtourl.py000066400000000000000000000320301466565367000220200ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Handler for mailto: links. """ import re import urllib.parse from email._parseaddr import AddressList from . import urlbase from .. import log, LOG_CHECK, strformat, url as urlutil from dns import resolver from ..network import iputil from .const import WARN_MAIL_NO_MX_HOST def getaddresses(addr): """Return list of email addresses from given field value.""" parsed = [mail for name, mail in AddressList(addr).addresslist if mail] if parsed: addresses = parsed elif addr: # we could not parse any mail addresses, so try with the raw string addresses = [addr] else: addresses = [] return addresses def is_quoted(addr): """Return True iff mail address string is quoted.""" return addr.startswith('"') and addr.endswith('"') def is_literal(domain): """Return True iff domain string is a literal.""" return domain.startswith('[') and domain.endswith(']') _remove_quoted = re.compile(r'\\.').sub _quotes = re.compile(r'["\\]') def is_missing_quote(addr): """Return True iff mail address is not correctly quoted.""" return _quotes.match(_remove_quoted("", addr[1:-1])) # list of CGI keys to search for email addresses EMAIL_CGI_ADDRESS = ("to", "cc", "bcc") EMAIL_CGI_SUBJECT = "subject" class MailtoUrl(urlbase.UrlBase): """ Url link with mailto scheme. """ def build_url(self): """Call super.build_url(), extract list of mail addresses from URL, and check their syntax. """ super().build_url() self.addresses = set() self.subject = None self.parse_addresses() if self.addresses: for addr in sorted(self.addresses): self.check_email_syntax(addr) if not self.valid: break elif not self.subject: self.add_warning( _("No mail addresses or email subject found in `%(url)s'.") % {"url": self.url} ) def parse_addresses(self): """Parse all mail addresses out of the URL target. Also parses optional CGI headers like "?to=foo@example.org". Stores parsed addresses in the self.addresses set. """ # cut off leading mailto: and unquote url = urllib.parse.unquote(self.base_url[7:], self.encoding) # search for cc, bcc, to and store in headers mode = 0 # 0=default, 1=quote, 2=esc quote = None i = 0 for i, c in enumerate(url): if mode == 0: if c == '?': break elif c in '<"': quote = c mode = 1 elif c == '\\': mode = 2 elif mode == 1: if c == '"' and quote == '"': mode = 0 elif c == '>' and quote == '<': mode = 0 elif mode == 2: mode = 0 if i < (len(url) - 1): self.addresses.update(getaddresses(url[:i])) try: headers = urllib.parse.parse_qs(url[(i + 1):], strict_parsing=True) for key, vals in headers.items(): if key.lower() in EMAIL_CGI_ADDRESS: # Only the first header value is added self.addresses.update( getaddresses(urllib.parse.unquote(vals[0], self.encoding)) ) if key.lower() == EMAIL_CGI_SUBJECT: self.subject = vals[0] except ValueError as err: self.add_warning(_("Error parsing CGI values: %s") % str(err)) else: self.addresses.update(getaddresses(url)) log.debug(LOG_CHECK, "addresses: %s", self.addresses) def check_email_syntax(self, mail): """Check email syntax. The relevant RFCs: - How to check names (memo): https://tools.ietf.org/html/rfc3696 - Email address syntax https://tools.ietf.org/html/rfc2822 - SMTP protocol https://tools.ietf.org/html/rfc5321#section-4.1.3 - IPv6 https://tools.ietf.org/html/rfc4291#section-2.2 - Host syntax https://tools.ietf.org/html/rfc1123#section-2 """ # length checks # restrict email length to 256 characters # https://www.rfc-editor.org/errata_search.php?eid=1003 if len(mail) > 256: self.set_result( _( "Mail address `%(addr)s' too long. Allowed 256 chars," " was %(length)d chars." ) % {"addr": mail, "length": len(mail)}, valid=False, overwrite=False, ) return if "@" not in mail: self.set_result( _("Missing `@' in mail address `%(addr)s'.") % {"addr": mail}, valid=False, overwrite=False, ) return # note: be sure to use rsplit since "@" can occur in local part local, domain = mail.rsplit("@", 1) if not local: self.set_result( _("Missing local part of mail address `%(addr)s'.") % {"addr": mail}, valid=False, overwrite=False, ) return if not domain: self.set_result( _("Missing domain part of mail address `%(addr)s'.") % {"addr": mail}, valid=False, overwrite=False, ) return if len(local) > 64: self.set_result( _( "Local part of mail address `%(addr)s' too long." " Allowed 64 chars, was %(length)d chars." ) % {"addr": mail, "length": len(local)}, valid=False, overwrite=False, ) return if len(domain) > 255: self.set_result( _( "Domain part of mail address `%(addr)s' too long." " Allowed 255 chars, was %(length)d chars." ) % {"addr": mail, "length": len(local)}, valid=False, overwrite=False, ) return # local part syntax check # Rules taken from https://tools.ietf.org/html/rfc3696#section-3 if is_quoted(local): if is_missing_quote(local): self.set_result( _("Unquoted double quote or backslash in mail address `%(addr)s'.") % {"addr": mail}, valid=False, overwrite=False, ) return else: if local.startswith("."): self.set_result( _("Local part of mail address `%(addr)s' may not start with a dot.") % {"addr": mail}, valid=False, overwrite=False, ) return if local.endswith("."): self.set_result( _("Local part of mail address `%(addr)s' may not end with a dot.") % {"addr": mail}, valid=False, overwrite=False, ) return if ".." in local: self.set_result( _("Local part of mail address `%(addr)s' may not contain two dots.") % {"addr": mail}, valid=False, overwrite=False, ) return for char in '@ \\",[]': if char in local.replace(f"\\{char}", ""): self.set_result( _( "Local part of mail address `%(addr)s' contains" " unquoted character `%(char)s." ) % {"addr": mail, "char": char}, valid=False, overwrite=False, ) return # domain part syntax check if is_literal(domain): # it's an IP address ip = domain[1:-1] if ip.startswith("IPv6:"): ip = ip[5:] if not iputil.is_valid_ip(ip): self.set_result( _("Domain part of mail address `%(addr)s' has invalid IP.") % {"addr": mail}, valid=False, overwrite=False, ) return else: # it's a domain name if not urlutil.is_safe_domain(domain): self.set_result( _("Invalid domain part of mail address `%(addr)s'.") % {"addr": mail}, valid=False, overwrite=False, ) return if domain.endswith(".") or domain.split(".")[-1].isdigit(): self.set_result( _("Invalid top level domain part of mail address `%(addr)s'.") % {"addr": mail}, valid=False, overwrite=False, ) return def check_connection(self): """ Verify a list of email addresses. If one address fails, the whole list will fail. For each mail address the MX DNS records are found. If no MX records are found, print a warning and try to look for A DNS records. If no A records are found either print an error. """ for mail in sorted(self.addresses): self.check_smtp_domain(mail) if not self.valid: break def check_smtp_domain(self, mail): """ Check a single mail address. """ from dns.exception import DNSException log.debug(LOG_CHECK, "checking mail address %r", mail) mail = strformat.ascii_safe(mail) username, domain = mail.rsplit('@', 1) log.debug(LOG_CHECK, "looking up MX mailhost %r", domain) try: answers = resolver.resolve(domain, 'MX', search=True) except DNSException: answers = [] if len(answers) == 0: self.add_warning( _("No MX mail host for %(domain)s found.") % {'domain': domain}, tag=WARN_MAIL_NO_MX_HOST, ) try: answers = resolver.resolve(domain, 'A', search=True) except DNSException: answers = [] if len(answers) == 0: self.set_result( _("No host for %(domain)s found.") % {'domain': domain}, valid=False, overwrite=True, ) return # set preference to zero mxdata = [(0, rdata.to_text(omit_final_dot=True)) for rdata in answers] else: from dns.rdtypes.mxbase import MXBase mxdata = [ (rdata.preference, rdata.exchange.to_text(omit_final_dot=True)) for rdata in answers if isinstance(rdata, MXBase) ] if not mxdata: self.set_result( _("Got invalid DNS answer %(answer)s for %(domain)s.") % {'answer': answers, 'domain': domain}, valid=False, overwrite=True, ) return # sort according to preference (lower preference means this # host should be preferred) mxdata.sort() # debug output log.debug(LOG_CHECK, "found %d MX mailhosts:", len(answers)) for preference, host in mxdata: log.debug(LOG_CHECK, "MX host %r, preference %d", host, preference) self.set_result(_("Valid mail address syntax")) def set_cache_url(self): """ The cache url is a comma separated list of emails. """ emails = ",".join(sorted(self.addresses)) self.cache_url = f"{self.scheme}:{emails}" def can_get_content(self): """ mailto: URLs do not have any content @return: False @rtype: bool """ return False linkchecker-10.5.0/linkcheck/checker/unknownurl.py000066400000000000000000000331571466565367000222450ustar00rootroot00000000000000# Copyright (C) 2001-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Handle uncheckable URLs. """ import re from . import urlbase class UnknownUrl(urlbase.UrlBase): """Handle unknown or just plain broken URLs.""" def build_url(self): """Only logs that this URL is unknown.""" super().build_url() if self.is_ignored(): self.add_info( _("%(scheme)s URL ignored.") % {"scheme": self.scheme.capitalize()} ) self.set_result(_("ignored")) else: self.set_result(_("URL is unrecognized or has invalid syntax"), valid=False) def is_ignored(self): """Return True if this URL scheme is ignored.""" return is_unknown_scheme(self.scheme) def can_get_content(self): """Unknown URLs have no content. @return: False @rtype: bool """ return False # do not edit anything below since these entries are generated from # scripts/update_iana_uri_schemes.sh # DO NOT REMOVE # from https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml ignored_schemes_permanent = r""" |aaa # Diameter Protocol |aaas # Diameter Protocol with Secure Transport |about # about |acap # application configuration access protocol |acct # acct |cap # Calendar Access Protocol |cid # content identifier |coap # coap |coap\+tcp # coap+tcp (see [reviewer notes]) |coap\+ws # coap+ws (see [reviewer notes]) |coaps # coaps |coaps\+tcp # coaps+tcp (see [reviewer notes]) |coaps\+ws # coaps+ws (see [reviewer notes]) |crid # TV-Anytime Content Reference Identifier |data # data |dav # dav |dict # dictionary service protocol |dns # Domain Name System |dtn # DTNRG research and development |example # example |geo # Geographic Locations |go # go |gopher # The Gopher Protocol |h323 # H.323 |iax # Inter-Asterisk eXchange Version 2 |icap # Internet Content Adaptation Protocol |im # Instant Messaging |imap # internet message access protocol |info # Information Assets with Identifiers in Public Namespaces. [RFC4452] (section 3) defines an "info" registry of public namespaces, which is maintained by NISO and can be accessed from [http://info-uri.info/]. |ipn # ipn |ipp # Internet Printing Protocol |ipps # Internet Printing Protocol over HTTPS |iris # Internet Registry Information Service |iris\.beep # iris.beep |iris\.lwz # iris.lwz |iris\.xpc # iris.xpc |iris\.xpcs # iris.xpcs |jabber # jabber |ldap # Lightweight Directory Access Protocol |leaptofrogans # leaptofrogans |mid # message identifier |msrp # Message Session Relay Protocol |msrps # Message Session Relay Protocol Secure |mt # Matter protocol on-boarding payloads that are encoded for use in QR Codes and/or NFC Tags |mtqp # Message Tracking Query Protocol |mupdate # Mailbox Update (MUPDATE) Protocol |news # USENET news |nfs # network file system protocol |ni # ni |nih # nih |nntp # USENET news using NNTP access |opaquelocktoken # opaquelocktokent |pkcs11 # PKCS#11 |pop # Post Office Protocol v3 |pres # Presence |reload # reload |rtsp # Real-Time Streaming Protocol (RTSP) |rtsps # Real-Time Streaming Protocol (RTSP) over TLS |rtspu # Real-Time Streaming Protocol (RTSP) over unreliable datagram transport |service # service location |session # session |shttp # Secure Hypertext Transfer Protocol |sieve # ManageSieve Protocol |sip # session initiation protocol |sips # secure session initiation protocol |sms # Short Message Service |snmp # Simple Network Management Protocol |soap\.beep # soap.beep |soap\.beeps # soap.beeps |stun # stun |stuns # stuns |tag # tag |tel # telephone |telnet # Reference to interactive sessions |tftp # Trivial File Transfer Protocol |thismessage # multipart/related relative reference resolution |tip # Transaction Internet Protocol |tn3270 # Interactive 3270 emulation sessions |turn # turn |turns # turns |tv # TV Broadcasts |urn # Uniform Resource Names |vemmi # versatile multimedia interface |vnc # Remote Framebuffer Protocol |ws # WebSocket connections |wss # Encrypted WebSocket connections |xcon # xcon |xcon\-userid # xcon-userid |xmlrpc\.beep # xmlrpc.beep |xmlrpc\.beeps # xmlrpc.beeps |xmpp # Extensible Messaging and Presence Protocol |z39\.50r # Z39.50 Retrieval |z39\.50s # Z39.50 Session """ ignored_schemes_provisional = r""" |acd # acd |acr # acr |adiumxtra # adiumxtra |adt # adt |afp # afp |afs # Andrew File System global file names |aim # aim |amss # amss |android # android |appdata # appdata |apt # apt |ar # ar |ark # ark |at # at (see [reviewer notes]) |attachment # attachment |aw # aw |barion # barion |beshare # beshare |bitcoin # bitcoin |bitcoincash # bitcoincash |blob # blob |bluetooth # bluetooth |bolo # bolo |brid # brid |browserext # browserext |cabal # cabal |calculator # calculator |callto # callto |cast # cast |casts # casts |chrome # chrome |chrome\-extension # chrome-extension |com\-eventbrite\-attendee # com-eventbrite-attendee |content # content |content\-type # content-type |cstr # cstr |cvs # cvs |dab # dab |dat # dat |dhttp # dhttp (see [reviewer notes]) |diaspora # diaspora |did # did |dis # dis |dlna\-playcontainer # dlna-playcontainer |dlna\-playsingle # dlna-playsingle |dntp # dntp |doi # doi |dpp # dpp |drm # drm |dtmi # dtmi |dvb # dvb |dvx # dvx |dweb # dweb |ed2k # ed2k |eid # eid |elsi # elsi |embedded # embedded |ens # ens |ethereum # ethereum |facetime # facetime |feed # feed |feedready # feedready |fido # fido |finger # finger |first\-run\-pen\-experience # first-run-pen-experience |fish # fish |fm # fm |fuchsia\-pkg # fuchsia-pkg |gg # gg |git # git |gitoid # gitoid |gizmoproject # gizmoproject |graph # graph |gtalk # gtalk |ham # ham |hcap # hcap |hcp # hcp |hs20 # hs20 |hxxp # hxxp |hxxps # hxxps |hydrazone # hydrazone |hyper # hyper |icon # icon |iotdisco # iotdisco |ipfs # ipfs |ipns # ipns |irc # irc |irc6 # irc6 |ircs # ircs |isostore # isostore |itms # itms |jar # jar |jms # Java Message Service |keyparc # keyparc |lastfm # lastfm |lbry # lbry |ldaps # ldaps |lid # lid |lorawan # lorawan |lpa # lpa |lvlt # lvlt |machineProvisioningProgressReporter # Windows Autopilot Modern Device Management status updates |magnet # magnet |maps # maps |market # market |matrix # matrix |message # message |microsoft\.windows\.camera # microsoft.windows.camera |microsoft\.windows\.camera\.multipicker # microsoft.windows.camera.multipicker |microsoft\.windows\.camera\.picker # microsoft.windows.camera.picker |mms # mms |mongodb # mongodb |moz # moz |ms\-access # ms-access |ms\-appinstaller # ms-appinstaller |ms\-browser\-extension # ms-browser-extension |ms\-calculator # ms-calculator |ms\-drive\-to # ms-drive-to |ms\-enrollment # ms-enrollment |ms\-excel # ms-excel |ms\-eyecontrolspeech # ms-eyecontrolspeech |ms\-gamebarservices # ms-gamebarservices |ms\-gamingoverlay # ms-gamingoverlay |ms\-getoffice # ms-getoffice |ms\-help # ms-help |ms\-infopath # ms-infopath |ms\-inputapp # ms-inputapp |ms\-launchremotedesktop # ms-launchremotedesktop |ms\-lockscreencomponent\-config # ms-lockscreencomponent-config |ms\-media\-stream\-id # ms-media-stream-id |ms\-meetnow # ms-meetnow |ms\-mixedrealitycapture # ms-mixedrealitycapture |ms\-mobileplans # ms-mobileplans |ms\-newsandinterests # ms-newsandinterests |ms\-officeapp # ms-officeapp |ms\-people # ms-people |ms\-personacard # ms-personacard |ms\-powerpoint # ms-powerpoint |ms\-project # ms-project |ms\-publisher # ms-publisher |ms\-recall # ms-recall |ms\-remotedesktop # ms-remotedesktop |ms\-remotedesktop\-launch # ms-remotedesktop-launch |ms\-restoretabcompanion # ms-restoretabcompanion |ms\-screenclip # ms-screenclip |ms\-screensketch # ms-screensketch |ms\-search # ms-search |ms\-search\-repair # ms-search-repair |ms\-secondary\-screen\-controller # ms-secondary-screen-controller |ms\-secondary\-screen\-setup # ms-secondary-screen-setup |ms\-settings # ms-settings |ms\-settings\-airplanemode # ms-settings-airplanemode |ms\-settings\-bluetooth # ms-settings-bluetooth |ms\-settings\-camera # ms-settings-camera |ms\-settings\-cellular # ms-settings-cellular |ms\-settings\-cloudstorage # ms-settings-cloudstorage |ms\-settings\-connectabledevices # ms-settings-connectabledevices |ms\-settings\-displays\-topology # ms-settings-displays-topology |ms\-settings\-emailandaccounts # ms-settings-emailandaccounts |ms\-settings\-language # ms-settings-language |ms\-settings\-location # ms-settings-location |ms\-settings\-lock # ms-settings-lock |ms\-settings\-nfctransactions # ms-settings-nfctransactions |ms\-settings\-notifications # ms-settings-notifications |ms\-settings\-power # ms-settings-power |ms\-settings\-privacy # ms-settings-privacy |ms\-settings\-proximity # ms-settings-proximity |ms\-settings\-screenrotation # ms-settings-screenrotation |ms\-settings\-wifi # ms-settings-wifi |ms\-settings\-workplace # ms-settings-workplace |ms\-spd # ms-spd |ms\-stickers # ms-stickers |ms\-sttoverlay # ms-sttoverlay |ms\-transit\-to # ms-transit-to |ms\-useractivityset # ms-useractivityset |ms\-virtualtouchpad # ms-virtualtouchpad |ms\-visio # ms-visio |ms\-walk\-to # ms-walk-to |ms\-whiteboard # ms-whiteboard |ms\-whiteboard\-cmd # ms-whiteboard-cmd |ms\-word # ms-word |msnim # msnim |mss # mss |mumble # mumble |mvn # mvn |mvrp # mvrp (see [reviewer notes]) |mvrps # mvrps (see [reviewer notes]) |notes # notes |num # Namespace Utility Modules |ocf # ocf |oid # oid |onenote # onenote |onenote\-cmd # onenote-cmd |openid # OpenID Connect |openpgp4fpr # openpgp4fpr |otpauth # otpauth |palm # palm |paparazzi # paparazzi |payto # payto |platform # platform |proxy # proxy |psyc # psyc |pttp # pttp |pwid # pwid |qb # qb |query # query |quic\-transport # quic-transport |redis # redis |rediss # rediss |res # res |resource # resource |rmi # rmi |rsync # rsync |rtmfp # rtmfp |rtmp # rtmp |sarif # sarif |secondlife # query |secret\-token # secret-token |sftp # query |sgn # sgn |shc # shc |simpleledger # simpleledger |simplex # simplex |skype # skype |smb # smb |smp # smp |smtp # smtp |soldat # soldat |spiffe # spiffe |spotify # spotify |ssb # ssb |ssh # ssh |starknet # starknet |steam # steam |submit # submit |svn # svn |swh # swh |swid # swid (see [reviewer notes]) |swidpath # swidpath (see [reviewer notes]) |taler # taler |teamspeak # teamspeak |teliaeid # teliaeid |things # things |tool # tool |udp # udp |unreal # unreal |ut2004 # ut2004 |uuid\-in\-package # uuid-in-package |v\-event # v-event |ventrilo # ventrilo |ves # ves |view\-source # view-source |vscode # vscode |vscode\-insiders # vscode-insiders |vsls # vsls |w3 # w3 (see [reviewer notes]) |wcr # wcr |web\+ap # web+ap |web3 # web3 |webcal # webcal |wifi # wifi |wtai # wtai |wyciwyg # wyciwyg |xfire # xfire |xftp # xftp |xrcp # xrcp |xri # xri |ymsgr # ymsgr """ ignored_schemes_historical = r""" |bb # bb |drop # drop |fax # fax |filesystem # filesystem |grd # grd |mailserver # Access to data available from mail servers |modem # modem |p1 # p1 |pack # pack |payment # payment |prospero # Prospero Directory Service |snews # NNTP over SSL/TLS |thzp # thzp |upt # upt |videotex # videotex |wais # Wide Area Information Servers |wpid # wpid |z39\.50 # Z39.50 information access """ ignored_schemes_other = r""" |clsid # Microsoft specific |find # Mozilla specific |gemini # Gemini protocol |isbn # ISBN (int. book numbers) |javascript # JavaScript |ms\-windows\-store # Microsoft Store |slack # Slack Technologies client |tg # Telegram |whatsapp # WhatsApp """ ignored_schemes = "^({}{}{}{})$".format( ignored_schemes_permanent, ignored_schemes_provisional, ignored_schemes_historical, ignored_schemes_other, ) ignored_schemes_re = re.compile(ignored_schemes, re.VERBOSE) is_unknown_scheme = ignored_schemes_re.match linkchecker-10.5.0/linkcheck/checker/urlbase.py000066400000000000000000001050241466565367000214510ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Base URL handler. """ # pylint: disable=assignment-from-none, catching-non-exception, no-member import sys import os import urllib.parse from urllib.request import urlopen import time import errno import socket from io import BytesIO from . import absolute_url, get_url_from from .. import ( log, LOG_CHECK, strformat, LinkCheckerError, url as urlutil, trace, get_link_pat, ) from ..htmlutil import htmlsoup from ..network import iputil from .const import ( WARN_URL_EFFECTIVE_URL, WARN_URL_ERROR_GETTING_CONTENT, WARN_URL_OBFUSCATED_IP, WARN_URL_CONTENT_SIZE_ZERO, WARN_URL_CONTENT_SIZE_TOO_LARGE, WARN_URL_CONTENT_TYPE_UNPARSEABLE, WARN_URL_WHITESPACE, URL_MAX_LENGTH, WARN_URL_TOO_LONG, ExcList, ExcSyntaxList, ExcNoCacheList, ) from ..url import url_fix_wayback_query # schemes that are invalid with an empty hostname scheme_requires_host = ("ftp", "http") def urljoin(parent, url): """ If url is relative, join parent and url. Else leave url as-is. @return: joined url """ if urlutil.url_is_absolute(url): return url return urllib.parse.urljoin(parent, url) def url_norm(url, encoding): """Wrapper for url.url_norm() to convert UnicodeError in LinkCheckerError.""" try: return urlutil.url_norm(url, encoding=encoding) except UnicodeError: msg = _("URL has unparsable domain name: %(name)s") % { "name": sys.exc_info()[1] } raise LinkCheckerError(msg) class UrlBase: """An URL with additional information like validity etc.""" # file types that can be parsed recursively ContentMimetypes = { "text/html": "html", "application/xhtml+xml": "html", # Include PHP file which helps when checking local .php files. # It does not harm other URL schemes like HTTP since HTTP servers # should not send this content type. They send text/html instead. "application/x-httpd-php": "html", "text/css": "css", "application/vnd.adobe.flash.movie": "swf", "application/x-shockwave-flash": "swf", "application/msword": "word", "text/plain+linkchecker": "text", "text/plain+opera": "opera", "text/plain+chromium": "chromium", "application/x-plist+safari": "safari", "text/vnd.wap.wml": "wml", "application/xml+sitemap": "sitemap", "application/xml+sitemapindex": "sitemapindex", "application/pdf": "pdf", "application/x-pdf": "pdf", } # Read in 16kb chunks ReadChunkBytes = 1024 * 16 def __init__( self, base_url, recursion_level, aggregate, parent_url=None, base_ref=None, line=-1, column=-1, page=-1, name="", url_encoding=None, extern=None, ): """ Initialize check data, and store given variables. @param base_url: unquoted and possibly unnormed url @param recursion_level: on what check level lies the base url @param aggregate: aggregate instance @param parent_url: quoted and normed url of parent or None @param base_ref: quoted and normed url of or None @param line: line number of url in parent content @param column: column number of url in parent content @param page: page number of url in parent content @param name: name of url or empty @param url_encoding: encoding of URL or None @param extern: None or (is_extern, is_strict) """ self.reset() self.init( base_ref, base_url, parent_url, recursion_level, aggregate, line, column, page, name, url_encoding, extern, ) self.check_syntax() if recursion_level == 0: self.add_intern_pattern() self.set_extern(self.url) if self.extern[0] and self.extern[1]: self.add_info( _("The URL is outside of the domain filter, checked only syntax.") ) if not self.has_result: self.set_result(_("filtered")) def init( self, base_ref, base_url, parent_url, recursion_level, aggregate, line, column, page, name, url_encoding, extern, ): """ Initialize internal data. """ self.base_ref = base_ref if self.base_ref is not None: assert isinstance(self.base_ref, str), repr(self.base_ref) self.base_url = base_url.strip() if base_url else base_url if self.base_url is not None: assert isinstance(self.base_url, str), repr(self.base_url) self.parent_url = parent_url if self.parent_url is not None: assert isinstance(self.parent_url, str), repr(self.parent_url) self.recursion_level = recursion_level self.aggregate = aggregate self.line = line self.column = column self.page = page self.name = name assert isinstance(self.name, str), repr(self.name) self.encoding = url_encoding self.extern = extern if self.base_ref: assert not urlutil.url_needs_quoting(self.base_ref), ( "unquoted base reference URL %r" % self.base_ref ) if self.parent_url: assert not urlutil.url_needs_quoting(self.parent_url), ( "unquoted parent URL %r" % self.parent_url ) url = absolute_url(self.base_url, base_ref, parent_url) # assume file link if no scheme is found self.scheme = url.split(":", 1)[0].lower() or "file" if self.base_url != base_url: self.add_warning( _("Leading or trailing whitespace in URL `%(url)s'.") % {"url": base_url}, tag=WARN_URL_WHITESPACE, ) self.ignore_errors = self.aggregate.config['ignoreerrors'] def reset(self): """ Reset all variables to default values. """ # self.url is constructed by self.build_url() out of base_url # and (base_ref or parent) as absolute and normed url. # This the real url we use when checking so it also referred to # as 'real url' self.url = None # a split version of url for convenience self.urlparts = None # the scheme, host, port and anchor part of url self.scheme = self.host = self.port = self.anchor = None # the result message string and flag self.result = "" self.has_result = False # valid or not self.valid = True # list of warnings (without duplicates) self.warnings = [] # list of infos self.info = [] # content size self.size = -1 # last modification time of content in HTTP-date format # as specified in RFC2616 chapter 3.3.1 self.modified = None # download time self.dltime = -1 # check time self.checktime = 0 # connection object self.url_connection = None # data of url content, (data == None) means no data is available self.data = None # url content data encoding self.content_encoding = None # url content as a Unicode string self.text = None # url content as a Beautiful Soup object self.soup = None # cache url is set by build_url() calling set_cache_url() self.cache_url = None # extern flags (is_extern, is_strict) self.extern = None # flag if the result should be cached self.caching = True # title is either the URL or parsed from content self.title = None # flag if content should be checked or not self.do_check_content = True # MIME content type self.content_type = "" # URLs seen through redirections self.aliases = [] # error messages (regular expressions) to ignore self.ignore_errors = [] def set_result(self, msg, valid=True, overwrite=False): """ Set result string and validity. """ if self.has_result and not overwrite: log.warn( LOG_CHECK, "Double result %r (previous %r) for %s", msg, self.result, self, ) else: self.has_result = True if not msg: log.warn(LOG_CHECK, "Empty result for %s", self) self.result = msg self.valid = valid if not self.valid: for url_regex, msg_regex in self.ignore_errors: if not url_regex.search(self.url): continue if not msg_regex.search(self.result): continue self.valid = True self.result = f"Ignored: {self.result}" # free content data self.data = None def get_title(self): """Return title of page the URL refers to. This is per default the filename or the URL.""" if self.title is None: url = "" if self.base_url: url = self.base_url elif self.url: url = self.url self.title = url if "/" in url: title = url.rsplit("/", 1)[1] if title: self.title = title return self.title def is_content_type_parseable(self): """ Return True iff the content type of this url is parseable. """ if self.content_type in self.ContentMimetypes: return True log.debug( LOG_CHECK, "URL with content type %r is not parseable", self.content_type, ) if self.recursion_level == 0: self.add_warning( _("The URL with content type %r is not parseable.") % self.content_type, tag=WARN_URL_CONTENT_TYPE_UNPARSEABLE, ) return False def is_parseable(self): """ Return True iff content of this url is parseable. """ return False def is_html(self): """Return True iff content of this url is HTML formatted.""" return self._is_ctype("html") def is_css(self): """Return True iff content of this url is CSS stylesheet.""" return self._is_ctype("css") def _is_ctype(self, ctype): """Return True iff content is valid and of the given type.""" if not self.valid: return False mime = self.content_type return self.ContentMimetypes.get(mime) == ctype def is_http(self): """Return True for *http://* or *https://* URLs.""" return self.scheme in ("http", "https") def is_file(self): """Return True for *file://* URLs.""" return self.scheme == "file" def is_directory(self): """Return True if current URL represents a directory.""" return False def is_local(self): """Return True for local (ie. *file://*) URLs.""" return self.is_file() def should_ignore_warning(self, tag): """Return true if a warning should be ignored""" log.debug(LOG_CHECK, "ignorewarnings(%s): %s, %s", self.url, tag, repr(self.aggregate.config["ignorewarnings"])) if tag in self.aggregate.config["ignorewarnings"]: return True ignore_warnings = self.aggregate.config["ignorewarningsforurls"] for url_regex, name_regex in ignore_warnings: log.debug(LOG_CHECK, "ignorewarningsforurl: considering '%s, %s'", url_regex, name_regex) if not url_regex.search(self.url): continue log.debug(LOG_CHECK, "ignorewarningsforurl: URL matches '%s'", self.url) if not name_regex.search(tag): log.debug(LOG_CHECK, "ignorewarningsforurl: tag doesn't match '%s'", tag) continue log.debug(LOG_CHECK, "ignorewarningsforurl: tag matches '%s'", tag) return True return False def add_warning(self, s, tag=None): """ Add a warning string. """ item = (tag, s) if item not in self.warnings: if self.should_ignore_warning(tag): self.add_info(s) else: self.warnings.append(item) def add_info(self, s): """ Add an info string. """ if s not in self.info: self.info.append(s) def set_cache_url(self): """Set the URL to be used for caching.""" if "AnchorCheck" in self.aggregate.config["enabledplugins"]: self.cache_url = self.url else: # remove anchor from cached target url since we assume # URLs with different anchors to have the same content self.cache_url = urlutil.urlunsplit(self.urlparts[:4] + ['']) log.debug(LOG_CHECK, "cache_url '%s'", self.cache_url) def check_syntax(self): """ Called before self.check(), this function inspects the url syntax. Success enables further checking, failure immediately logs this url. Syntax checks must not use any network resources. """ log.debug(LOG_CHECK, "checking syntax") if self.base_url is None: self.base_url = "" if not (self.base_url or self.parent_url): self.set_result(_("URL is empty"), valid=False) return try: self.build_url() self.check_url_warnings() except tuple(ExcSyntaxList) as msg: self.set_result(str(msg), valid=False) else: self.set_cache_url() def check_url_warnings(self): """Check URL name and length.""" effectiveurl = urlutil.urlunsplit(self.urlparts) if self.url != effectiveurl: self.add_warning( _("Effective URL %(url)r.") % {"url": effectiveurl}, tag=WARN_URL_EFFECTIVE_URL, ) self.url = effectiveurl if len(self.url) > URL_MAX_LENGTH and self.scheme != "data": args = dict(len=len(self.url), max=URL_MAX_LENGTH) self.add_warning( _("URL length %(len)d is longer than %(max)d.") % args, tag=WARN_URL_TOO_LONG, ) def build_url(self): """ Construct self.url and self.urlparts out of the given base url information self.base_url, self.parent_url and self.base_ref. """ # norm base url - can raise UnicodeError from url.idna_encode() base_url, is_idn = url_norm(self.base_url, self.encoding) # make url absolute if self.base_ref: # use base reference as parent url if ":" not in self.base_ref: # some websites have a relative base reference self.base_ref = urljoin(self.parent_url, self.base_ref) self.url = urljoin(self.base_ref, base_url) elif self.parent_url: # strip the parent url anchor urlparts = list(urllib.parse.urlsplit(self.parent_url)) urlparts[4] = "" parent_url = urlutil.urlunsplit(urlparts) self.url = urljoin(parent_url, base_url) else: self.url = base_url # urljoin can unnorm the url path, so norm it again urlparts = list(urllib.parse.urlsplit(self.url)) if urlparts[2]: urlparts[2] = urlutil.collapse_segments(urlparts[2]) if not urlparts[0].startswith("feed"): # restore second / in http[s]:// in wayback path urlparts[2] = url_fix_wayback_query(urlparts[2]) self.url = urlutil.urlunsplit(urlparts) self.urlparts = self.build_url_parts(self.url) # and unsplit again self.url = urlutil.urlunsplit(self.urlparts) def build_url_parts(self, url): """Set userinfo, host, port and anchor from url and return urlparts. Also checks for obfuscated IP addresses. """ split = urllib.parse.urlsplit(url) urlparts = list(split) # check userinfo@host:port syntax self.userinfo, host = urlutil.split_netloc(split.netloc) try: port = split.port except ValueError: raise LinkCheckerError( _("URL host %(host)r has invalid port") % {"host": host} ) if port is None: port = urlutil.default_ports.get(self.scheme, 0) if port is None: raise LinkCheckerError( _("URL host %(host)r has invalid port") % {"host": host} ) self.port = port # urllib.parse.SplitResult.hostname is lowercase self.host = split.hostname if self.scheme in scheme_requires_host: if not self.host: raise LinkCheckerError(_("URL has empty hostname")) self.check_obfuscated_ip() if not self.port or self.port == urlutil.default_ports.get(self.scheme): host = self.host else: host = f"{self.host}:{self.port}" if self.userinfo: urlparts[1] = f"{self.userinfo}@{host}" else: urlparts[1] = host # save anchor for later checking self.anchor = split.fragment if self.anchor is not None: assert isinstance(self.anchor, str), repr(self.anchor) return urlparts def check_obfuscated_ip(self): """Warn if host of this URL is obfuscated IP address.""" # check if self.host can be an IP address # check for obfuscated IP address if iputil.is_obfuscated_ip(self.host): ips = iputil.resolve_host(self.host) if ips: self.host = ips[0] self.add_warning( _("URL %(url)s has obfuscated IP address %(ip)s") % {"url": self.base_url, "ip": ips[0]}, tag=WARN_URL_OBFUSCATED_IP, ) def check(self): """Main check function for checking this URL.""" if self.aggregate.config["trace"]: trace.trace_on() try: self.local_check() except OSError: # on Unix, ctrl-c can raise # error: (4, 'Interrupted system call') etype, value = sys.exc_info()[:2] if etype == errno.EINTR: raise KeyboardInterrupt(value) else: raise def local_check(self): """Local check function can be overridden in subclasses.""" log.debug(LOG_CHECK, "Checking %s", self) # strict extern URLs should not be checked assert not self.extern[1], 'checking strict extern URL' # check connection log.debug(LOG_CHECK, "checking connection") try: self.check_connection() self.set_content_type() self.add_size_info() self.aggregate.plugin_manager.run_connection_plugins(self) except tuple(ExcList) as exc: value = self.handle_exception() # make nicer error msg for unknown hosts if isinstance(exc, socket.error) and exc.args[0] == -2: value = _('Hostname not found') elif isinstance(exc, UnicodeError): # idna.encode(host) failed value = _('Bad hostname %(host)r: %(msg)s') % { 'host': self.host, 'msg': value, } self.set_result(value, valid=False) def check_content(self): """Check content of URL. @return: True if content can be parsed, else False """ if self.do_check_content and self.valid: # check content and recursion try: if self.can_get_content(): self.aggregate.plugin_manager.run_content_plugins(self) if self.allows_recursion(): return True except tuple(ExcList): value = self.handle_exception() self.add_warning( _("could not get content: %(msg)s") % {"msg": value}, tag=WARN_URL_ERROR_GETTING_CONTENT, ) return False def close_connection(self): """ Close an opened url connection. """ if self.url_connection is None: # no connection is open return try: self.url_connection.close() except Exception: # ignore close errors pass self.url_connection = None def handle_exception(self): """ An exception occurred. Log it and set the cache flag. """ etype, evalue = sys.exc_info()[:2] log.debug( LOG_CHECK, "Error in %s: %s %s", self.url, etype, evalue, exception=True ) # note: etype must be the exact class, not a subclass if ( (etype in ExcNoCacheList) or (etype == socket.error and evalue.args[0] == errno.EBADF) or not evalue ): # EBADF occurs when operating on an already socket self.caching = False # format message ": " errmsg = etype.__name__ if evalue: errmsg += f": {evalue}" # limit length to 240 return strformat.limit(errmsg, length=240) def check_connection(self): """ The basic connection check uses urlopen to initialize a connection object. """ self.url_connection = urlopen(self.url) def add_size_info(self): """Set size of URL content (if any).. Should be overridden in subclasses.""" maxbytes = self.aggregate.config["maxfilesizedownload"] if self.size > maxbytes: self.add_warning( _("Content size %(size)s is larger than %(maxbytes)s.") % dict( size=strformat.strsize(self.size), maxbytes=strformat.strsize(maxbytes), ), tag=WARN_URL_CONTENT_SIZE_TOO_LARGE, ) def allows_simple_recursion(self): """Check recursion level and extern status.""" rec_level = self.aggregate.config["recursionlevel"] if rec_level >= 0 and self.recursion_level >= rec_level: log.debug(LOG_CHECK, "... no, maximum recursion level reached.") return False if self.extern[0]: log.debug(LOG_CHECK, "... no, extern.") return False return True def allows_recursion(self): """ Return True iff we can recurse into the url's content. """ log.debug(LOG_CHECK, "checking recursion of %r ...", self.url) if not self.valid: log.debug(LOG_CHECK, "... no, invalid.") return False if not self.can_get_content(): log.debug(LOG_CHECK, "... no, cannot get content.") return False if not self.allows_simple_recursion(): return False if self.size > self.aggregate.config["maxfilesizeparse"]: log.debug(LOG_CHECK, "... no, maximum parse size.") return False if not self.is_parseable(): log.debug(LOG_CHECK, "... no, not parseable.") return False if not self.content_allows_robots(): log.debug(LOG_CHECK, "... no, robots.") return False log.debug(LOG_CHECK, "... yes, recursion.") return True def content_allows_robots(self): """Returns True: only check robots.txt on HTTP links.""" return True def set_extern(self, url): """ Match URL against extern and intern link patterns. If no pattern matches the URL is extern. Sets self.extern to a tuple (bool, bool) with content (is_extern, is_strict). @return: None """ if self.extern: return if not url: self.extern = (1, 1) return for entry in self.aggregate.config["externlinks"]: match = entry['pattern'].search(url) if (entry['negate'] and not match) or (match and not entry['negate']): log.debug(LOG_CHECK, "Extern URL %r", url) self.extern = (1, entry['strict']) return for entry in self.aggregate.config["internlinks"]: match = entry['pattern'].search(url) if (entry['negate'] and not match) or (match and not entry['negate']): log.debug(LOG_CHECK, "Intern URL %r", url) self.extern = (0, 0) return if self.aggregate.config['checkextern']: self.extern = (1, 0) else: self.extern = (1, 1) def set_content_type(self): """Set content MIME type. Should be overridden in subclasses.""" pass def can_get_content(self): """Indicate whether url get_content() can be called.""" return self.size <= self.aggregate.config["maxfilesizedownload"] def download_content(self): log.debug(LOG_CHECK, "Get content of %r", self.url) t = time.time() content = self.read_content() self.size = len(content) self.dltime = time.time() - t if self.size == 0: self.add_warning(_("Content size is zero."), tag=WARN_URL_CONTENT_SIZE_ZERO) else: self.aggregate.add_downloaded_bytes(self.size) return content def get_soup(self): if self.soup is None: self.get_content() return self.soup def get_raw_content(self): if self.data is None: self.data = self.download_content() return self.data def get_content(self, encoding=None): if self.text is None: self.get_raw_content() self.soup = htmlsoup.make_soup(self.data, encoding) # Sometimes soup.original_encoding is None! Better mangled text # than an internal crash, eh? ISO-8859-1 is a safe fallback in the # sense that any binary blob can be decoded, it'll never cause a # UnicodeDecodeError. log.debug( LOG_CHECK, "Beautiful Soup detected %s", self.soup.original_encoding ) self.content_encoding = self.soup.original_encoding or 'ISO-8859-1' log.debug(LOG_CHECK, "Content encoding %s", self.content_encoding) self.text = self.data.decode(self.content_encoding) return self.text def read_content(self): """Return data for this URL. Can be overridden in subclasses.""" buf = BytesIO() data = self.read_content_chunk() while data: if buf.tell() + len(data) > self.aggregate.config["maxfilesizedownload"]: raise LinkCheckerError(_("File size too large")) buf.write(data) data = self.read_content_chunk() return buf.getvalue() def read_content_chunk(self): """Read one chunk of content from this URL. Precondition: url_connection is an opened URL. """ return self.url_connection.read(self.ReadChunkBytes) def get_user_password(self): """Get tuple (user, password) from configured authentication. Both user and password can be None. """ if self.userinfo: # URL itself has authentication info split = urllib.parse.urlsplit(self.url) return (split.username, split.password) return self.aggregate.config.get_user_password(self.url) def add_url(self, url, line=0, column=0, page=0, name="", base=None, parent=None): """Add new URL to queue.""" if base: base_ref = urlutil.url_norm(base, encoding=self.content_encoding)[0] else: base_ref = None url_data = get_url_from( url, self.recursion_level + 1, self.aggregate, parent_url=self.url if parent is None else parent, base_ref=base_ref, line=line, column=column, page=page, name=name, parent_content_type=self.content_type, url_encoding=self.content_encoding, ) self.aggregate.urlqueue.put(url_data) def serialized(self, sep=os.linesep): """ Return serialized url check data as unicode string. """ return sep.join( [ "%s link" % self.scheme, "base_url=%r" % self.base_url, "parent_url=%r" % self.parent_url, "base_ref=%r" % self.base_ref, "recursion_level=%d" % self.recursion_level, "url_connection=%s" % self.url_connection, "line=%s" % self.line, "column=%s" % self.column, "page=%d" % self.page, "name=%r" % self.name, "anchor=%r" % self.anchor, "cache_url=%s" % self.cache_url, ] ) def get_intern_pattern(self, url=None): """Get pattern for intern URL matching. @param url: the URL to set intern pattern for, else self.url @type url: unicode or None @return: non-empty regex pattern or None @rtype: String or None """ return None def add_intern_pattern(self, url=None): """Add intern URL regex to config.""" try: pat = self.get_intern_pattern(url=url) if pat: log.debug(LOG_CHECK, "Add intern pattern %r", pat) self.aggregate.config['internlinks'].append(get_link_pat(pat)) except UnicodeError as msg: res = _("URL has unparsable domain name: %(domain)s") % {"domain": msg} self.set_result(res, valid=False) def __str__(self): """ Get URL info. @return: URL info @rtype: unicode """ return self.serialized() def __bytes__(self): """ Get URL info. @return: URL info, encoded with the output logger encoding @rtype: string """ s = str(self) return self.aggregate.config['logger'].encode(s) def __repr__(self): """ Get URL info. @return: URL info @rtype: unicode """ return f'<{self.serialized(sep=", ")}>' def to_wire_dict(self): """Return a simplified transport object for logging and caching. The transport object must contain these attributes: - url_data.valid: bool Indicates if URL is valid - url_data.result: unicode Result string - url_data.warnings: list of tuples (tag, warning message) List of tagged warnings for this URL. - url_data.name: unicode string or None name of URL (eg. filename or link name) - url_data.parent_url: unicode or None Parent URL - url_data.base_ref: unicode HTML base reference URL of parent - url_data.url: unicode Fully qualified URL. - url_data.domain: unicode URL domain part. - url_data.checktime: int Number of seconds needed to check this link, default: zero. - url_data.dltime: int Number of seconds needed to download URL content, default: -1 - url_data.size: int Size of downloaded URL content, default: -1 - url_data.info: list of unicode Additional information about this URL. - url_data.line: int Line number of this URL at parent document, or None - url_data.column: int Column number of this URL at parent document, or None - url_data.page: int Page number of this URL at parent document, or -1 - url_data.cache_url: unicode Cache url for this URL. - url_data.content_type: unicode MIME content type for URL content. - url_data.level: int Recursion level until reaching this URL from start URL - url_data.last_modified: datetime Last modification date of retrieved page (or None). """ return dict( valid=self.valid, extern=self.extern[0], result=self.result, warnings=self.warnings[:], name=self.name or "", title=self.get_title(), parent_url=self.parent_url or "", base_ref=self.base_ref or "", base_url=self.base_url or "", url=self.url or "", domain=(self.urlparts[1] if self.urlparts else ""), checktime=self.checktime, dltime=self.dltime, size=self.size, info=self.info, line=self.line, column=self.column, page=self.page, cache_url=self.cache_url, content_type=self.content_type, level=self.recursion_level, modified=self.modified, ) def to_wire(self): """Return compact UrlData object with information from to_wire_dict(). """ return CompactUrlData(self.to_wire_dict()) urlDataAttr = [ 'valid', 'extern', 'result', 'warnings', 'name', 'title', 'parent_url', 'base_ref', 'base_url', 'url', 'domain', 'checktime', 'dltime', 'size', 'info', 'modified', 'line', 'column', 'page', 'cache_url', 'content_type', 'level', ] class CompactUrlData: """Store selected UrlData attributes in slots to minimize memory usage.""" __slots__ = urlDataAttr def __init__(self, wired_url_data): '''Set all attributes according to the dictionary wired_url_data''' for attr in urlDataAttr: setattr(self, attr, wired_url_data[attr]) linkchecker-10.5.0/linkcheck/cmdline.py000066400000000000000000000046251466565367000200300ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Utility functions suitable for command line clients. """ import sys import argparse from . import checker, fileutil, strformat, plugins from .director import console class LCArgumentParser(argparse.ArgumentParser): """Custom argument parser to format help text.""" def print_help(self, file=sys.stdout): """Print a help message to stdout.""" msg = self.format_help() if fileutil.is_tty(file): strformat.paginate(msg) else: print(msg, file=file) def print_version(exit_code=0): """Print the program version and exit.""" console.print_version() sys.exit(exit_code) def print_plugins(folders, exit_code=0): """Print available plugins and exit.""" modules = plugins.get_plugin_modules(folders) pluginclasses = sorted( plugins.get_plugin_classes(modules), key=lambda x: x.__name__ ) for pluginclass in pluginclasses: print(pluginclass.__name__) doc = strformat.wrap(pluginclass.__doc__, 80) print(strformat.indent(doc)) print() sys.exit(exit_code) def print_usage(msg, exit_code=2): """Print a program msg text to stderr and exit.""" program = sys.argv[0] print(_("Error: %(msg)s") % {"msg": msg}, file=console.stderr) print( _("Execute '%(program)s -h' for help") % {"program": program}, file=console.stderr, ) sys.exit(exit_code) def aggregate_url(aggregate, url, err_exit_code=2): """Append given commandline URL to input queue.""" get_url_from = checker.get_url_from url = checker.guess_url(url) url_data = get_url_from(url, 0, aggregate, extern=(0, 0)) aggregate.urlqueue.put(url_data) linkchecker-10.5.0/linkcheck/colorama.py000066400000000000000000000117661466565367000202160ustar00rootroot00000000000000# These functions are part of the python-colorama module # They have been adjusted slightly for LinkChecker # # Copyright: (C) 2010 Jonathan Hartley # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. Neither the name(s) of the copyright holders nor the # names of its contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from ctypes import (windll, byref, Structure, c_char, c_short, c_uint32, c_ushort, ArgumentError, WinError) # from winbase.h STDOUT = -11 STDERR = -12 handles = { STDOUT: windll.kernel32.GetStdHandle(STDOUT), STDERR: windll.kernel32.GetStdHandle(STDERR), } SHORT = c_short WORD = c_ushort DWORD = c_uint32 TCHAR = c_char class COORD(Structure): """struct in wincon.h""" _fields_ = [ ('X', SHORT), ('Y', SHORT), ] class SMALL_RECT(Structure): """struct in wincon.h.""" _fields_ = [ ("Left", SHORT), ("Top", SHORT), ("Right", SHORT), ("Bottom", SHORT), ] class CONSOLE_SCREEN_BUFFER_INFO(Structure): """struct in wincon.h.""" _fields_ = [ ("dwSize", COORD), ("dwCursorPosition", COORD), ("wAttributes", WORD), ("srWindow", SMALL_RECT), ("dwMaximumWindowSize", COORD), ] def __str__(self): """Get string representation of console screen buffer info.""" return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % ( self.dwSize.Y, self.dwSize.X , self.dwCursorPosition.Y, self.dwCursorPosition.X , self.wAttributes , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X ) def GetConsoleScreenBufferInfo(stream_id=STDOUT): """Get console screen buffer info object.""" handle = handles[stream_id] csbi = CONSOLE_SCREEN_BUFFER_INFO() success = windll.kernel32.GetConsoleScreenBufferInfo( handle, byref(csbi)) if not success: raise WinError() return csbi def SetConsoleTextAttribute(stream_id, attrs): """Set a console text attribute.""" handle = handles[stream_id] return windll.kernel32.SetConsoleTextAttribute(handle, attrs) # from wincon.h BLACK = 0 BLUE = 1 GREEN = 2 CYAN = 3 RED = 4 MAGENTA = 5 YELLOW = 6 GREY = 7 # from wincon.h NORMAL = 0x00 # dim text, dim background BRIGHT = 0x08 # bright text, dim background _default_foreground = None _default_background = None _default_style = None def init(): """Initialize foreground and background attributes.""" global _default_foreground, _default_background, _default_style try: attrs = GetConsoleScreenBufferInfo().wAttributes except (ArgumentError, OSError): _default_foreground = GREY _default_background = BLACK _default_style = NORMAL else: _default_foreground = attrs & 7 _default_background = (attrs >> 4) & 7 _default_style = attrs & BRIGHT def get_attrs(foreground, background, style): """Get foreground and background attributes.""" return foreground + (background << 4) + style def set_console(stream=STDOUT, foreground=None, background=None, style=None): """Set console foreground and background attributes.""" if foreground is None: foreground = _default_foreground if background is None: background = _default_background if style is None: style = _default_style attrs = get_attrs(foreground, background, style) SetConsoleTextAttribute(stream, attrs) def reset_console(stream=STDOUT): """Reset the console.""" set_console(stream=stream) def get_console_size(): """Get the console size.""" return GetConsoleScreenBufferInfo().dwSize linkchecker-10.5.0/linkcheck/command/000077500000000000000000000000001466565367000174525ustar00rootroot00000000000000linkchecker-10.5.0/linkcheck/command/__init__.py000066400000000000000000000000001466565367000215510ustar00rootroot00000000000000linkchecker-10.5.0/linkcheck/command/arg_parser.py000066400000000000000000000351301466565367000221530ustar00rootroot00000000000000# Copyright (C) 2000-2016 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Create command line arguments. """ import argparse from .. import checker, logconf, logger, COMMAND_NAME from ..cmdline import LCArgumentParser # usage texts Notes = _( """NOTES o URLs on the command line starting with "ftp." are treated like "ftp://ftp.", URLs starting with "www." are treated like "http://www.". You can also give local files as arguments. o If you have your system configured to automatically establish a connection to the internet (e.g. with diald), it will connect when checking links not pointing to your local system. See the --ignore-url option on how to prevent this. o Javascript links are currently ignored. o If your platform does not support threading, LinkChecker disables it automatically. o You can supply multiple user/password pairs in a configuration file. """ ) ProxySupport = _( """PROXY SUPPORT To use a proxy on Unix or Windows set $http_proxy or $https_proxy to the proxy URL. The URL should be of the form "http://[:@][:]". LinkChecker also detects manual proxy settings of Internet Explorer under Windows systems. On a Mac use the Internet Config to select a proxy. LinkChecker honors the $no_proxy environment variable. It can be a list of domain names for which no proxy will be used. Setting a HTTP proxy on Unix for example looks like this: export http_proxy="http://proxy.example.com:8080" Proxy authentication is also supported: export http_proxy="http://user1:mypass@proxy.example.org:8081" Setting a proxy on the Windows command prompt: set http_proxy=http://proxy.example.com:8080 """ ) RegularExpressions = _( """REGULAR EXPRESSIONS Only Python regular expressions are accepted by LinkChecker. See https://docs.python.org/howto/regex.html for an introduction in regular expressions. The only addition is that a leading exclamation mark negates the regular expression. """ ) CookieFormat = _( """COOKIE FILES A cookie file contains standard RFC 805 header data with the following possible names: Scheme (optional) Sets the scheme the cookies are valid for; default scheme is 'http'. Host (required) Sets the domain the cookies are valid for. Path (optional) Gives the path the cookies are value for; default path is '/'. Set-cookie (optional) Set cookie name/value. Can be given more than once. Multiple entries are separated by a blank line. The example below will send two cookies to all URLs starting with 'http://example.org/hello/' and one to all URLs starting with 'https://example.com/': Host: example.org Path: /hello Set-cookie: ID="smee" Set-cookie: spam="egg" Scheme: https Host: example.com Set-cookie: baggage="elitist"; comment="hologram" """ ) Retval = _( r"""RETURN VALUE The return value is non-zero when o invalid links were found or o warnings were found warnings are enabled o a program error occurred """ ) Examples = _( r"""EXAMPLES The most common use checks the given domain recursively, plus any single URL pointing outside of the domain: linkchecker http://www.example.org/ Beware that this checks the whole site which can have several hundred thousands URLs. Use the -r option to restrict the recursion depth. Don't connect to mailto: hosts, only check their URL syntax. All other links are checked as usual: linkchecker --ignore-url=^mailto: www.example.org Checking local HTML files on Unix: linkchecker ../bla.html subdir/blubber.html Checking a local HTML file on Windows: linkchecker c:\temp\test.html You can skip the "http://" url part if the domain starts with "www.": linkchecker www.example.de You can skip the "ftp://" url part if the domain starts with "ftp.": linkchecker -r0 ftp.example.org """ ) LoggerTypes = _( r"""OUTPUT TYPES Note that by default only errors and warnings are logged. You should use the --verbose option to see valid URLs, and when outputting a sitemap graph format. text Standard text output, logging URLs in keyword: argument fashion. html Log URLs in keyword: argument fashion, formatted as HTML. Additionally has links to the referenced pages. Invalid URLs have HTML and CSS syntax check links appended. csv Log check result in CSV format with one URL per line. gml Log parent-child relations between linked URLs as a GML sitemap graph. dot Log parent-child relations between linked URLs as a DOT sitemap graph. gxml Log check result as a GraphXML sitemap graph. xml Log check result as machine-readable XML. sql Log check result as SQL script with INSERT commands. An example script to create the initial SQL table is included as create.sql. failures Suitable for cron jobs. Logs the check result into a file $XDG_DATA_HOME/linkchecker/failures which only contains entries with invalid URLs and the number of times they have failed. none Logs nothing. Suitable for debugging or checking the exit code. """ ) Warnings = ( _( r"""IGNORE WARNINGS The following warnings are recognized in the 'ignorewarnings' config file entry: """ ) + "\n".join( [ f" o {tag} - {desc}" for tag, desc in sorted(checker.const.Warnings.items()) ] ) ) Epilog = "\n".join( ( Examples, LoggerTypes, RegularExpressions, CookieFormat, ProxySupport, Notes, Retval, Warnings, ) ) class ArgParser(LCArgumentParser): """Create a parser for command line arguments""" def __init__(self): super().__init__( epilog=Epilog, formatter_class=argparse.RawDescriptionHelpFormatter, prog=COMMAND_NAME, ) # ================== general options ===================== group = self.add_argument_group(_("General options")) group.add_argument( "-f", "--config", dest="configfile", metavar="FILENAME", help=_( "Use FILENAME as configuration file. Per default LinkChecker uses\n" "$XDG_CONFIG_HOME/linkchecker/linkcheckerrc (under Windows\n" "%%HOMEPATH%%\\.config\\linkchecker\\linkcheckerrc)." ), ) group.add_argument( "-t", "--threads", type=int, metavar="NUMBER", help=_( "Generate no more than the given number of threads. Default number\n" "of threads is 10. To disable threading specify a non-positive number." ), ) group.add_argument( "-V", "--version", action="store_true", help=_("Print version and exit.") ) group.add_argument( "--list-plugins", action="store_true", dest="listplugins", help=_("Print available check plugins and exit."), ) group.add_argument( "--stdin", action="store_true", help=_("Read list of white-space separated URLs to check from stdin."), ) # ================== output options ===================== group = self.add_argument_group(_("Output options")) group.add_argument( "-D", "--debug", action="append", metavar="STRING", help=_( "Print debugging output for the given logger.\n" "Available loggers are %(lognamelist)s.\n" "Specifying 'all' is an alias for specifying all available loggers.\n" "The option can be given multiple times to debug with more\n" "than one logger.\n" "\n" "For accurate results, threading will be disabled during debug runs." ) % {"lognamelist": logconf.lognamelist}, ) group.add_argument( "-F", "--file-output", action="append", dest="fileoutput", metavar="TYPE[/ENCODING[/FILENAME]]", help=_( "Output to a file linkchecker-out.TYPE, $XDG_DATA_HOME/linkchecker/failures for\n" "'failures' output, or FILENAME if specified.\n" "The ENCODING specifies the output encoding, the default is that of your\n" "locale.\n" "Valid encodings are listed at " "https://docs.python.org/library/codecs.html#standard-encodings.\n" "The FILENAME and ENCODING parts of the 'none' output type will be ignored,\n" "else if the file already exists, it will be overwritten.\n" "You can specify this option more than once. Valid file output types\n" "are %(loggertypes)s. You can specify this option multiple times to output\n" "to more than one file. Default is no file output. Note that you can\n" "suppress all console output with the option '-o none'." ) % {"loggertypes": logger.LoggerKeys}, ) group.add_argument( "--no-status", action="store_false", default=None, dest="status", help=_("Do not print check status messages."), ) group.add_argument( "--no-warnings", action="store_false", dest="warnings", help=_("Don't log warnings. Default is to log warnings."), ) group.add_argument( "-o", "--output", dest="output", metavar="TYPE[/ENCODING]", help=_( "Specify output as %(loggertypes)s. Default output type is text.\n" "The ENCODING specifies the output encoding, the default is that of your\n" "locale.\n" "Valid encodings are listed at " "https://docs.python.org/library/codecs.html#standard-encodings." ) % {"loggertypes": logger.LoggerKeys}, ) group.add_argument( "--profile", action="store_true", dest="profile", help=argparse.SUPPRESS ) group.add_argument( "-q", "--quiet", action="store_true", dest="quiet", help=_( "Quiet operation, an alias for '-o none'.\n" "This is only useful with -F." ), ) group.add_argument( "--trace", action="store_true", dest="trace", help=argparse.SUPPRESS) group.add_argument( "-v", "--verbose", action="store_true", dest="verbose", help=_("Log all URLs. Default is to log only errors and warnings."), ) # =================== checking options ==================== group = self.add_argument_group(_("Checking options")) group.add_argument( "--cookiefile", dest="cookiefile", metavar="FILENAME", help=_( "Read a file with initial cookie data. The cookie data format is\n" "explained below." ), ) # const because store_false doesn't detect absent flags group.add_argument( "--no-robots", action="store_const", const=False, dest="norobotstxt", help=_("Disable robots.txt checks"), ) group.add_argument( "--check-extern", action="store_true", dest="checkextern", help=_("""Check external URLs."""), ) group.add_argument( "--ignore-url", action="append", metavar="REGEX", dest="externstrict", help=_( "Only check syntax of URLs matching the given regular expression.\n" "This option can be given multiple times." ), ) group.add_argument( "--no-follow-url", action="append", metavar="REGEX", dest="extern", help=_( "Check but do not recurse into URLs matching the given regular\n" "expression. This option can be given multiple times." ), ) group.add_argument( "-p", "--password", action="store_true", dest="password", help=_( "Read a password from console and use it for HTTP and FTP authorization.\n" "For FTP the default password is 'anonymous@'. For HTTP there is\n" "no default password. See also -u." ), ) group.add_argument( "-r", "--recursion-level", type=int, dest="recursionlevel", metavar="NUMBER", help=_( "Check recursively all links up to given depth. A negative depth\n" "will enable infinite recursion. Default depth is infinite." ), ) group.add_argument( "--timeout", type=int, dest="timeout", metavar="NUMBER", help=_( "Set the timeout for connection attempts in seconds." ) ) group.add_argument( "-u", "--user", dest="username", metavar="STRING", help=_( "Try the given username for HTTP and FTP authorization.\n" "For FTP the default username is 'anonymous'. For HTTP there is\n" "no default username. See also -p." ), ) group.add_argument( "--user-agent", dest="useragent", metavar="STRING", help=_( "Specify the User-Agent string to send to the HTTP server, for example\n" '"Mozilla/4.0". The default is "LinkChecker/X.Y" where X.Y is the current\n' "version of LinkChecker." ), ) self.add_argument("url", nargs="*") linkchecker-10.5.0/linkcheck/command/linkchecker.py000066400000000000000000000171011466565367000223060ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Check HTML pages for broken links. This is the commandline client. Run this file with the -h option to see how it's done. """ import os import pprint import signal import sys import traceback from .arg_parser import ArgParser from .setup_config import setup_config from .. import configuration from .. import fileutil from .. import log from .. import logconf from .. import LinkCheckerError from ..cmdline import aggregate_url, print_usage from ..director import console, check_urls, get_aggregate from ..logconf import LOG_CHECK, LOG_CMDLINE, LOG_THREAD from ..strformat import stripurl def drop_privileges(): """Make sure to drop root privileges on POSIX systems.""" if os.name != 'posix': return if os.geteuid() == 0: log.warn( LOG_CHECK, _( "Running as root user; " "dropping privileges by changing user to nobody." ), ) import pwd os.seteuid(pwd.getpwnam('nobody')[3]) def linkchecker(): if hasattr(signal, "SIGUSR1"): # install SIGUSR1 handler from ..decorators import signal_handler @signal_handler(signal.SIGUSR1) def print_threadstacks(sig, frame): """Print stack traces of all running threads.""" log.warn(LOG_THREAD, "*** STACKTRACE START ***") for threadId, stack in sys._current_frames().items(): log.warn(LOG_THREAD, "# ThreadID: %s" % threadId) for filename, lineno, name, line in traceback.extract_stack(stack): log.warn( LOG_THREAD, 'File: "%s", line %d, in %s' % (filename, lineno, name) ) line = line.strip() if line: log.warn(LOG_THREAD, " %s" % line) log.warn(LOG_THREAD, "*** STACKTRACE END ***") logconf.init_log_config() # optional modules has_argcomplete = fileutil.has_module("argcomplete") has_profile = fileutil.has_module("yappi") has_meliae = fileutil.has_module("meliae") # default profiling filename _profile = "linkchecker.prof" def read_stdin_urls(): """Read list of URLs, separated by white-space, from stdin.""" num = 0 while True: lines = sys.stdin.readlines(8 * 1024) if not lines: break for line in lines: for url in line.split(): num += 1 if num % 10000 == 0: log.info(LOG_CMDLINE, "Read %d URLs from stdin", num) yield url # instantiate command line option parser argparser = ArgParser() # build a config object for this check session config = configuration.Configuration() config.set_status_logger(console.StatusLogger()) # ================= auto completion ===================== if has_argcomplete: import argcomplete argcomplete.autocomplete(argparser) # read and parse command line options and arguments options = argparser.parse_args() # configure application logging if options.debug: allowed_debugs = logconf.lognames.keys() for _name in options.debug: if _name not in allowed_debugs: print_usage(_("Invalid debug level %(level)r") % {"level": _name}) logconf.set_debug(options.debug) elif options.quiet: logconf.reset_loglevel() log.debug( LOG_CMDLINE, _("Python %(version)s on %(platform)s") % {"version": sys.version, "platform": sys.platform}, ) # read configuration files try: files = [] if options.configfile: path = configuration.normpath(options.configfile) if not fileutil.is_valid_config_source(path): raise LinkCheckerError( _("Config file %s does not exist.") % options.configfile) elif not fileutil.is_readable(path): raise LinkCheckerError( _("Could not read config file %s.") % options.configfile) else: files.append(path) config.read(files=files) except LinkCheckerError as msg: # config error print_usage(str(msg)) drop_privileges() # set up config object using options setup_config(config, options) # now sanitize the configuration config.sanitize() log.debug(LOG_CMDLINE, "configuration: %s", pprint.pformat(sorted(config.items()))) # prepare checking queue aggregate = get_aggregate(config) if options.trace: # enable thread tracing config["trace"] = True # start trace in mainthread from .. import trace trace.trace_filter([r"^linkcheck"]) trace.trace_on() # add urls to queue if options.stdin: for url in read_stdin_urls(): aggregate_url(aggregate, url) elif options.url: for url in options.url: aggregate_url(aggregate, stripurl(url)) else: log.warn(LOG_CMDLINE, _("no files or URLs given")) # set up profiling do_profile = False if options.profile: if has_profile: if os.path.exists(_profile): print( _( "Overwrite profiling file %(file)r?\n" "Press Ctrl-C to cancel, RETURN to continue." ) % {"file": _profile} ) try: input() except KeyboardInterrupt: print("", _("Canceled."), file=sys.stderr, sep="\n") sys.exit(1) do_profile = True else: log.warn( LOG_CMDLINE, _( "The `yappi' Python module is not installed," " therefore the --profile option is disabled." ), ) # finally, start checking if do_profile: import yappi yappi.start() check_urls(aggregate) yappi.stop() yappi.get_func_stats().save(_profile) else: check_urls(aggregate) if config["debugmemory"]: from .. import memoryutil if has_meliae: log.info(LOG_CMDLINE, _("Dumping memory statistics...")) filename = memoryutil.write_memory_dump() message = _("The memory dump has been written to `%(filename)s'.") log.info(LOG_CMDLINE, message % dict(filename=filename)) else: log.warn(LOG_CMDLINE, memoryutil.MemoryDebugMsg) stats = config["logger"].stats # on internal errors, exit with status 2 if stats.internal_errors: sys.exit(2) # on errors or printed warnings, exit with status 1 if stats.errors or (stats.warnings_printed and config["warnings"]): sys.exit(1) linkchecker-10.5.0/linkcheck/command/setup_config.py000066400000000000000000000177741466565367000225310ustar00rootroot00000000000000# Copyright (C) 2000-2016 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Configure linkchecker using command-line options and configuration. """ import codecs import getpass from .. import fileutil from .. import i18n from .. import logger from .. import LOG_CMDLINE from .. import get_link_pat, log from ..cmdline import print_version, print_usage, print_plugins def has_encoding(encoding): """Detect if Python can encode in a certain encoding.""" try: codecs.lookup(encoding) return True except LookupError: return False def setup_config(config, options): """Set up linkchecker based on command-line options and configuration""" _username = None _password = None # test if running with -O if options.debug and not __debug__: log.warn(LOG_CMDLINE, _("Running with python -O disables debugging.")) # apply commandline options and arguments to configuration constructauth = False if options.version: print_version() if not options.warnings: config["warnings"] = options.warnings if options.externstrict: pats = [get_link_pat(arg, strict=True) for arg in options.externstrict] config["externlinks"].extend(pats) if options.extern: pats = [get_link_pat(arg) for arg in options.extern] config["externlinks"].extend(pats) if options.norobotstxt is not None: config["robotstxt"] = options.norobotstxt if options.checkextern: config["checkextern"] = True elif not config["checkextern"]: log.info( LOG_CMDLINE, "Checking intern URLs only; use --check-extern to check extern URLs.", ) if options.output: if "/" in options.output: logtype, encoding = options.output.split("/", 1) else: logtype, encoding = options.output, i18n.default_encoding logtype = logtype.lower() if logtype == "blacklist": log.warn( LOG_CMDLINE, _("blacklist is deprecated for option %(option)s, " "using failures instead") % {"option": "'-o, --output'"} ) logtype = "failures" if logtype not in logger.LoggerNames: print_usage( _("Unknown logger type %(type)r in %(output)r for option %(option)s") % {"type": logtype, "output": options.output, "option": "'-o, --output'"} ) if logtype != "none" and not has_encoding(encoding): print_usage( _("Unknown encoding %(encoding)r in %(output)r for option %(option)s") % { "encoding": encoding, "output": options.output, "option": "'-o, --output'", } ) config["output"] = logtype config["logger"] = config.logger_new(logtype, encoding=encoding) if options.fileoutput: ns = {"fileoutput": 1} for arg in options.fileoutput: ftype = arg # look for (optional) filename and encoding if "/" in ftype: ftype, suffix = ftype.split("/", 1) if suffix: if has_encoding(suffix): # it was an encoding ns["encoding"] = suffix elif "/" in suffix: # look for (optional) encoding encoding, filename = suffix.split("/", 1) if has_encoding(encoding): ns["encoding"] = encoding ns["filename"] = filename else: ns["filename"] = suffix else: ns["filename"] = suffix if ftype == "blacklist": log.warn( LOG_CMDLINE, _("blacklist logger is deprecated for option %(option)s, " "using failures instead") % {"option": "'-F, --file-output'"} ) ftype = "failures" if ftype not in logger.LoggerNames: print_usage( _("Unknown logger type %(type)r in %(output)r" " for option %(option)s") % { "type": ftype, "output": options.fileoutput, "option": "'-F, --file-output'", } ) if ftype != "none" and "encoding" in ns \ and not has_encoding(ns["encoding"]): print_usage( _("Unknown encoding %(encoding)r in %(output)r" " for option %(option)s") % { "encoding": ns["encoding"], "output": options.fileoutput, "option": "'-F, --file-output'", } ) new_logger = config.logger_new(ftype, **ns) config["fileoutput"].append(new_logger) if options.username: _username = options.username constructauth = True if options.password: if _username: msg = _("Enter LinkChecker HTTP/FTP password for user %(user)s:") % { "user": _username } else: msg = _("Enter LinkChecker HTTP/FTP password:") _password = getpass.getpass(msg) constructauth = True if options.quiet: config["logger"] = config.logger_new("none") if options.recursionlevel is not None: config["recursionlevel"] = options.recursionlevel if options.status is not None: config["status"] = options.status if options.threads is not None: if options.threads < 1: options.threads = 0 config["threads"] = options.threads if options.timeout is not None: if options.timeout > 0: config["timeout"] = options.timeout else: print_usage( _("Illegal argument %(arg)r for option %(option)s") % {"arg": options.timeout, "option": "'--timeout'"} ) if options.listplugins: print_plugins(config["pluginfolders"]) if options.verbose: if options.verbose: config["verbose"] = True config["warnings"] = True if constructauth: config.add_auth(pattern=".+", user=_username, password=_password) # read missing passwords for entry in config["authentication"]: if entry["password"] is None: attrs = entry.copy() attrs["strpattern"] = attrs["pattern"].pattern msg = ( _("Enter LinkChecker password for user %(user)s at %(strpattern)s:") % attrs ) entry["password"] = getpass.getpass(msg) if options.useragent is not None: config["useragent"] = options.useragent if options.cookiefile is not None: if not fileutil.is_valid_config_source(options.cookiefile): print_usage( _("Cookie file %s does not exist.") % options.cookiefile) elif not fileutil.is_readable(options.cookiefile): print_usage( _("Could not read cookie file %s") % options.cookiefile) else: config["cookiefile"] = options.cookiefile linkchecker-10.5.0/linkcheck/configuration/000077500000000000000000000000001466565367000207035ustar00rootroot00000000000000linkchecker-10.5.0/linkcheck/configuration/__init__.py000066400000000000000000000336721466565367000230270ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Store metadata and options. """ import importlib.resources import os import re import urllib.parse import shutil import socket from .. import log, LOG_CHECK, PACKAGE_NAME, fileutil from . import confparse try: from .. import _release except ImportError: raise SystemExit('Run "hatchling build --hooks-only" first') Version = _release.__version__ ReleaseDate = _release.__release_date__ CopyrightYear = _release.__copyright_year__ AppName = _release.__app_name__ App = AppName + " " + Version Author = _release.__author__ HtmlAuthor = Author.replace(' ', ' ') Copyright = f"Copyright (C) 2000-2016 Bastian Kleineidam, 2010-{CopyrightYear} {Author}" HtmlCopyright = ( "Copyright © 2000-2016 Bastian Kleineidam, " f"2010-{CopyrightYear} {HtmlAuthor}") HtmlAppInfo = App + ", " + HtmlCopyright Url = _release.__url__ SupportUrl = _release.__support_url__ UserAgent = f"Mozilla/5.0 (compatible; {AppName}/{Version}; +{Url})" Freeware = ( AppName + """ comes with ABSOLUTELY NO WARRANTY! This is free software, and you are welcome to redistribute it under certain conditions. Look at the file `COPYING' within this distribution.""" ) def normpath(path): """Norm given system path with all available norm or expand functions in os.path.""" expanded = os.path.expanduser(os.path.expandvars(path)) return os.path.normcase(os.path.normpath(expanded)) # List Python modules in the form (module, name, version attribute) Modules = ( # required modules ("bs4", "Beautiful Soup", "__version__"), ("dns.version", "dnspython", "version"), ("requests", "Requests", "__version__"), # optional modules ("argcomplete", "Argcomplete", None), ("GeoIP", "GeoIP", 'lib_version'), # on Unix systems ("pygeoip", "GeoIP", 'lib_version'), # on Windows systems ("sqlite3", "SQLite", 'sqlite_version'), ("meliae", "Meliae", '__version__'), ) def get_modules_info(): """Return unicode string with detected module info.""" module_infos = [] for (mod, name, version_attr) in Modules: try: module = importlib.import_module(mod) except ModuleNotFoundError: continue if version_attr and (attr := getattr(module, version_attr, None)): version = attr() if callable(attr) else attr module_infos.append(f"{name} {version}") else: # ignore attribute errors in case library developers # change the version information attribute module_infos.append(name) return "Modules: %s" % (", ".join(module_infos)) def get_system_cert_file(): """Try to find a system-wide SSL certificate file. @return: the filename to the cert file @raises: ValueError when no system cert file could be found """ if os.name == 'posix': filename = "/etc/ssl/certs/ca-certificates.crt" if os.path.isfile(filename): return filename msg = "no system certificate file found" raise ValueError(msg) def get_certifi_file(): """Get the SSL certifications installed by the certifi package. @return: the filename to the cert file @rtype: string @raises: ImportError when certifi is not installed or ValueError when the file is not found """ import certifi filename = certifi.where() if os.path.isfile(filename): return filename msg = "%s not found; check your certifi installation" % filename raise ValueError(msg) # dynamic options class Configuration(dict): """ Storage for configuration options. Options can both be given from the command line as well as from configuration files. """ def __init__(self): """ Initialize the default options. """ super().__init__() # checking options self["allowedschemes"] = [] self['cookiefile'] = None self['robotstxt'] = True self["debugmemory"] = False self["localwebroot"] = None self["maxfilesizeparse"] = 1 * 1024 * 1024 self["maxfilesizedownload"] = 5 * 1024 * 1024 self["maxnumurls"] = None self["maxrunseconds"] = None self["maxrequestspersecond"] = 10 self["maxhttpredirects"] = 10 self["sslverify"] = True self["threads"] = 10 self["timeout"] = 60 self["aborttimeout"] = 300 self["recursionlevel"] = -1 self["useragent"] = UserAgent self["resultcachesize"] = 100000 # authentication self["authentication"] = [] self["loginurl"] = None self["loginuserfield"] = "login" self["loginpasswordfield"] = "password" self["loginextrafields"] = {} # filtering self["externlinks"] = [] self["ignoreerrors"] = [] self["ignorewarnings"] = [] self["ignorewarningsforurls"] = [] self["internlinks"] = [] self["checkextern"] = False # plugins self["pluginfolders"] = get_plugin_folders() self["enabledplugins"] = [] # output self['trace'] = False self['quiet'] = False self["verbose"] = False self["warnings"] = True self["fileoutput"] = [] self['output'] = 'text' self["status"] = True self["status_wait_seconds"] = 5 self['logger'] = None self.status_logger = None self.loggers = {} from ..logger import LoggerClasses for c in LoggerClasses: key = c.LoggerName self[key] = {} self.loggers[key] = c def set_status_logger(self, status_logger): """Set the status logger.""" self.status_logger = status_logger def logger_new(self, loggername, **kwargs): """Instantiate new logger and return it.""" args = self[loggername] args.update(kwargs) return self.loggers[loggername](**args) def logger_add(self, loggerclass): """Add a new logger type to the known loggers.""" self.loggers[loggerclass.LoggerName] = loggerclass self[loggerclass.LoggerName] = {} def read(self, files=None): """ Read settings from given config files. @raises: LinkCheckerError on syntax errors in the config file(s) """ if files is None: cfiles = [] else: cfiles = files[:] if not cfiles: userconf = get_user_config() if os.path.isfile(userconf): cfiles.append(userconf) # filter invalid files filtered_cfiles = [] for cfile in cfiles: if not fileutil.is_valid_config_source(cfile): log.warn(LOG_CHECK, _("Configuration file %r does not exist."), cfile) elif not fileutil.is_readable(cfile): log.warn(LOG_CHECK, _("Configuration file %r is not readable."), cfile) else: filtered_cfiles.append(cfile) log.debug(LOG_CHECK, "reading configuration from %s", filtered_cfiles) confparse.LCConfigParser(self).read(filtered_cfiles) def add_auth(self, user=None, password=None, pattern=None): """Add given authentication data.""" if not user or not pattern: log.warn( LOG_CHECK, _("missing user or URL pattern in authentication data.") ) return entry = dict(user=user, password=password, pattern=re.compile(pattern)) self["authentication"].append(entry) def get_user_password(self, url): """Get tuple (user, password) from configured authentication that matches the given URL. Both user and password can be None if not specified, or no authentication matches the given URL. """ for auth in self["authentication"]: if auth['pattern'].match(url): return (auth['user'], auth['password']) return (None, None) def get_connectionlimits(self): """Get dict with limit per connection type.""" return {key: self['maxconnections%s' % key] for key in ('http', 'https', 'ftp')} def sanitize(self): "Make sure the configuration is consistent." if self['logger'] is None: self.sanitize_logger() if self['loginurl']: self.sanitize_loginurl() self.sanitize_plugins() self.sanitize_ssl() # set default socket timeout socket.setdefaulttimeout(self['timeout']) def sanitize_logger(self): """Make logger configuration consistent.""" if not self['output']: log.warn(LOG_CHECK, _("activating text logger output.")) self['output'] = 'text' self['logger'] = self.logger_new(self['output']) def sanitize_loginurl(self): """Make login configuration consistent.""" url = self["loginurl"] disable = False if self.get_user_password(url) == (None, None): log.warn( LOG_CHECK, _("no user/password authentication data found for login URL."), ) disable = True if not url.lower().startswith(("http:", "https:")): log.warn(LOG_CHECK, _("login URL is not a HTTP URL.")) disable = True urlparts = urllib.parse.urlsplit(url) if not urlparts[0] or not urlparts[1] or not urlparts[2]: log.warn(LOG_CHECK, _("login URL is incomplete.")) disable = True if disable: log.warn(LOG_CHECK, _("disabling login URL %(url)s.") % {"url": url}) self["loginurl"] = None def sanitize_plugins(self): """Ensure each plugin is configurable.""" for plugin in self["enabledplugins"]: if plugin not in self: self[plugin] = {} def sanitize_ssl(self): """Use local installed certificate file if available. Tries to get system, then certifi certificate file.""" if self["sslverify"] is True: try: self["sslverify"] = get_system_cert_file() except ValueError: try: self["sslverify"] = get_certifi_file() except (ValueError, ImportError): pass def get_user_data(): """Get the user data folder. Returns "~/.linkchecker/" if this folder exists, "$XDG_DATA_HOME/linkchecker" if $XDG_DATA_HOME is set, else "~/.local/share/linkchecker". @rtype string """ homedotdir = normpath("~/.linkchecker/") userdata = ( homedotdir if os.path.isdir(homedotdir) else os.path.join( os.environ.get("XDG_DATA_HOME") or os.path.expanduser( os.path.join("~", ".local", "share")), "linkchecker") ) return userdata def get_plugin_folders(): """Get linkchecker plugin folders. Default is "$XDG_DATA_HOME/linkchecker/plugins/" if $XDG_DATA_HOME is set, else "~/.local/share/linkchecker/plugins/". "~/.linkchecker/plugins/" is also supported for backwards compatibility, and is used if it exists.""" folders = [] defaultfolder = os.path.join(get_user_data(), "plugins") if not os.path.exists(defaultfolder): try: make_userdir(defaultfolder) except Exception as errmsg: msg = _("could not create plugin directory %(dirname)r: %(errmsg)r") args = dict(dirname=defaultfolder, errmsg=errmsg) log.warn(LOG_CHECK, msg % args) if os.path.exists(defaultfolder): folders.append(defaultfolder) return folders def make_userdir(child): """Create a child directory.""" userdir = os.path.dirname(child) if not os.path.isdir(userdir): if os.name == 'nt': # Windows forbids filenames with leading dot unless # a trailing dot is added. userdir += "." os.makedirs(userdir, 0o700) def get_user_config(): """Get the user configuration filename. If the user configuration file does not exist, copy it from the initial configuration file. Returns path to user config file (which might not exist due to copy failures). @return configuration filename @rtype string """ # per user config settings homedotfile = normpath("~/.linkchecker/linkcheckerrc") userconf = ( homedotfile if os.path.isfile(homedotfile) else os.path.join( os.environ.get("XDG_CONFIG_HOME") or os.path.expanduser( os.path.join("~", ".config")), "linkchecker", "linkcheckerrc") ) if not os.path.exists(userconf): # initial config (with all options explained) with importlib.resources.path( f"{PACKAGE_NAME}.data", "linkcheckerrc") as initialconf: # copy the initial configuration to the user configuration try: make_userdir(userconf) shutil.copy(initialconf, userconf) except Exception as errmsg: msg = _( "could not copy initial configuration file %(src)r" " to %(dst)r: %(errmsg)r" ) args = dict(src=initialconf, dst=userconf, errmsg=errmsg) log.warn(LOG_CHECK, msg % args) return userconf def split_hosts(value): """Split comma-separated host list.""" return [host for host in value.split(", ") if host] linkchecker-10.5.0/linkcheck/configuration/confparse.py000066400000000000000000000334711466565367000232450ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """Parse configuration files""" from configparser import RawConfigParser from re import compile as re_compile import os from .. import ( LinkCheckerError, get_link_pat, LOG_CHECK, log, fileutil, plugins, logconf, ) def read_multiline(value): """Helper function reading multiline values.""" for line in value.splitlines(): line = line.strip() if not line or line.startswith('#'): continue yield line class LCConfigParser(RawConfigParser): """ Parse a LinkChecker configuration file. """ def __init__(self, config): """Initialize configuration.""" super().__init__() self.config = config def read(self, files): """Read settings from given config files. @raises: LinkCheckerError on syntax errors in the config file(s) """ assert isinstance(files, list), "Invalid file list %r" % files try: self.read_ok = super().read(files) if not self.sections(): raise LinkCheckerError( _("configuration files %s contain no sections.") % files) if len(self.read_ok) < len(files): failed_files = set(files) - set(self.read_ok) log.warn( LOG_CHECK, "Could not read configuration files %s.", failed_files ) # Read all the configuration parameters from the given files. self.read_checking_config() self.read_authentication_config() self.read_filtering_config() self.read_output_config() self.read_plugin_config() except Exception as msg: raise LinkCheckerError(_("Error parsing configuration: %s") % str(msg)) def read_string_option(self, section, option, allowempty=False): """Read a string option.""" if self.has_option(section, option): value = self.get(section, option) if not allowempty and not value: raise LinkCheckerError( _("invalid empty value for %s: %s\n") % (option, value) ) self.config[option] = value def read_boolean_option(self, section, option): """Read a boolean option.""" if self.has_option(section, option): self.config[option] = self.getboolean(section, option) def read_float_option(self, section, option, key=None, min=None, max=None): """Read a float option.""" if self.has_option(section, option): num = self.getfloat(section, option) if min is not None and num < min: raise LinkCheckerError( _("invalid value for %s: %d must not be less than %d") % (option, num, min) ) if max is not None and num < max: raise LinkCheckerError( _("invalid value for %s: %d must not be greater than %d") % (option, num, max) ) if key is None: key = option self.config[key] = num def read_int_option(self, section, option, key=None, min=None, max=None): """Read an integer option.""" if self.has_option(section, option): num = self.getint(section, option) if min is not None and num < min: raise LinkCheckerError( _("invalid value for %s: %d must not be less than %d") % (option, num, min) ) if max is not None and num < max: raise LinkCheckerError( _("invalid value for %s: %d must not be greater than %d") % (option, num, max) ) if key is None: key = option self.config[key] = num def read_output_config(self): """Read configuration options in section "output".""" section = "output" from ..logger import LoggerClasses if self.has_section("blacklist"): log.warn( LOG_CHECK, _("The blacklist section in linkcheckerrc is deprecated, " "please rename to failures") ) for opt in self.options("blacklist"): self.config["failures"][opt] = self.get("blacklist", opt) for c in LoggerClasses: key = c.LoggerName if self.has_section(key): for opt in self.options(key): self.config[key][opt] = self.get(key, opt) if self.has_option(key, 'parts'): val = self.get(key, 'parts') parts = [f.strip().lower() for f in val.split(',')] self.config[key]['parts'] = parts self.read_boolean_option(section, "warnings") if self.has_option(section, "verbose"): if self.getboolean(section, "verbose"): self.config["verbose"] = True self.config["warnings"] = True if self.has_option(section, "quiet"): if self.getboolean(section, "quiet"): self.config['output'] = 'none' self.config['quiet'] = True logconf.reset_loglevel() # if debug will be overwritten next if self.has_option(section, "debug"): val = self.get(section, "debug") parts = [f.strip().lower() for f in val.split(',')] logconf.set_debug(parts) self.read_boolean_option(section, "status") if self.has_option(section, "log"): val = self.get(section, "log").strip().lower() self.config['output'] = val if self.has_option(section, "fileoutput"): loggers = self.get(section, "fileoutput").split(",") # strip names from whitespace loggers = (x.strip().lower() for x in loggers) # no file output for the failures and none Logger from ..logger import LoggerNames loggers = ( x for x in loggers if x in LoggerNames and x not in ("failures", "none") ) for val in loggers: output = self.config.logger_new(val, fileoutput=1) self.config['fileoutput'].append(output) if self.has_option(section, "ignoreerrors"): for line in read_multiline(self.get(section, "ignoreerrors")): parts = line.split(maxsplit=1) if len(parts) == 1: parts.append('') self.config["ignoreerrors"].append(tuple( re_compile(part) for part in parts )) def read_checking_config(self): """Read configuration options in section "checking".""" section = "checking" self.read_int_option(section, "threads", min=-1) self.config['threads'] = max(0, self.config['threads']) self.read_int_option(section, "timeout", min=1) self.read_int_option(section, "aborttimeout", min=1) self.read_int_option(section, "recursionlevel", min=-1) self.read_string_option(section, "useragent") self.read_float_option(section, "maxrequestspersecond", min=0.001) self.read_int_option(section, "maxnumurls", min=0) self.read_int_option(section, "maxfilesizeparse", min=1) self.read_int_option(section, "maxfilesizedownload", min=1) if self.has_option(section, "allowedschemes"): self.config['allowedschemes'] = [ x.strip().lower() for x in self.get(section, 'allowedschemes').split(',') ] self.read_boolean_option(section, "debugmemory") self.read_string_option(section, "cookiefile") self.read_boolean_option(section, "robotstxt") self.read_string_option(section, "localwebroot") try: self.read_boolean_option(section, "sslverify") except ValueError: self.read_string_option(section, "sslverify") self.read_int_option(section, "maxrunseconds", min=0) self.read_int_option(section, "resultcachesize", min=0) def read_authentication_config(self): """Read configuration options in section "authentication".""" section = "authentication" password_fields = [] if self.has_option(section, "entry"): for val in read_multiline(self.get(section, "entry")): auth = val.split() if len(auth) == 3: self.config.add_auth( pattern=auth[0], user=auth[1], password=auth[2] ) password_fields.append(f"entry/{auth[0]}/{auth[1]}") elif len(auth) == 2: self.config.add_auth(pattern=auth[0], user=auth[1]) else: raise LinkCheckerError( _("missing auth part in entry %(val)r") % {"val": val} ) # read login URL and field names if self.has_option(section, "loginurl"): val = self.get(section, "loginurl").strip() if not ( val.lower().startswith("http:") or val.lower().startswith("https:") ): raise LinkCheckerError( _( "invalid login URL `%s'. Only " "HTTP and HTTPS URLs are supported." ) % val ) self.config["loginurl"] = val self.read_string_option(section, "loginuserfield") self.read_string_option(section, "loginpasswordfield") # read login extra fields if self.has_option(section, "loginextrafields"): for val in read_multiline(self.get(section, "loginextrafields")): name, value = val.split(":", 1) self.config["loginextrafields"][name] = value self.check_password_readable(section, password_fields) def check_password_readable(self, section, fields): """Check if there is a readable configuration file and print a warning.""" if not fields: return # The information which of the configuration files # included which option is not available. To avoid false positives, # a warning is only printed if exactly one file has been read. if len(self.read_ok) != 1: return fn = self.read_ok[0] if fileutil.is_accessable_by_others(fn): log.warn( LOG_CHECK, _( "The configuration file %s contains password information (in" " section [%s] and options %s) and the file is readable by" " others. Please make the file only readable by you." ), fn, section, fields, ) if os.name == 'posix': log.warn(LOG_CHECK, _("For example execute 'chmod go-rw %s'.") % fn) elif os.name == 'nt': log.warn( LOG_CHECK, _( "See %(url)s for more info on setting file permissions." ) % {"url": "https://support.microsoft.com/kb/308419"} ) def read_filtering_config(self): """ Read configuration options in section "filtering". """ section = "filtering" if self.has_option(section, "ignorewarnings"): self.config['ignorewarnings'] = [ f.strip().lower() for f in self.get(section, 'ignorewarnings').split(',') ] if self.has_option(section, "ignorewarningsforurls"): for line in read_multiline(self.get(section, "ignorewarningsforurls")): parts = line.split(maxsplit=1) if len(parts) == 1: parts.append('') self.config["ignorewarningsforurls"].append(tuple( re_compile(part) for part in parts )) if self.has_option(section, "ignore"): for line in read_multiline(self.get(section, "ignore")): pat = get_link_pat(line, strict=1) self.config["externlinks"].append(pat) if self.has_option(section, "nofollow"): for line in read_multiline(self.get(section, "nofollow")): pat = get_link_pat(line, strict=0) self.config["externlinks"].append(pat) if self.has_option(section, "internlinks"): pat = get_link_pat(self.get(section, "internlinks")) self.config["internlinks"].append(pat) self.read_boolean_option(section, "checkextern") def read_plugin_config(self): """Read plugin-specific configuration values.""" folders = self.config["pluginfolders"] modules = plugins.get_plugin_modules(folders) for pluginclass in plugins.get_plugin_classes(modules): section = pluginclass.__name__ if self.has_section(section): self.config["enabledplugins"].append(section) self.config[section] = pluginclass.read_config(self) linkchecker-10.5.0/linkcheck/containers.py000066400000000000000000000066051466565367000205620ustar00rootroot00000000000000# Copyright (C) 2004-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Special container classes. """ class LFUCache(dict): """Limited cache which purges least frequently used items.""" def __init__(self, size=1000): """Initialize internal LFU cache.""" super().__init__() if size < 1: raise ValueError("invalid cache size %d" % size) self.size = size def __setitem__(self, key, val): """Store given key/value.""" if key in self: # store value, do not increase number of uses super().__getitem__(key)[1] = val else: super().__setitem__(key, [0, val]) # check for size limit if len(self) > self.size: self.shrink() def shrink(self): """Shrink ca. 5% of entries.""" trim = int(0.05 * len(self)) if trim: items = super().items() # sorting function for items def keyfunc(x): return x[1][0] values = sorted(items, key=keyfunc) for item in values[0:trim]: del self[item[0]] def __getitem__(self, key): """Update key usage and return value.""" entry = super().__getitem__(key) entry[0] += 1 return entry[1] def uses(self, key): """Get number of uses for given key (without increasing the number of uses)""" return super().__getitem__(key)[0] def get(self, key, def_val=None): """Update key usage if found and return value, else return default.""" if key in self: return self[key] return def_val def setdefault(self, key, def_val=None): """Update key usage if found and return value, else set and return default.""" if key in self: return self[key] self[key] = def_val return def_val def items(self): """Return list of items, not updating usage count.""" return [(key, value[1]) for key, value in super().items()] def iteritems(self): """Return iterator of items, not updating usage count.""" for key, value in super().items(): yield (key, value[1]) def values(self): """Return list of values, not updating usage count.""" return [value[1] for value in super().values()] def itervalues(self): """Return iterator of values, not updating usage count.""" for value in super().values(): yield value[1] def popitem(self): """Remove and return an item.""" key, value = super().popitem() return (key, value[1]) def pop(self): """Remove and return a value.""" value = super().pop() return value[1] linkchecker-10.5.0/linkcheck/cookies.py000066400000000000000000000045421466565367000200470ustar00rootroot00000000000000# Copyright (C) 2005-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Parsing of cookies. """ from http.cookiejar import split_header_words import email import requests from . import LinkCheckerError def from_file(filename): """Parse cookie data from a text file in HTTP header format. @return: list of tuples (headers, scheme, host, path) """ entries = [] with open(filename) as fd: lines = [] for line in fd.readlines(): line = line.rstrip() if not line: if lines: entries.extend(from_headers("\r\n".join(lines))) lines = [] else: lines.append(line) if lines: entries.extend(from_headers("\r\n".join(lines))) if not entries: raise LinkCheckerError(_("No entries found")) return entries def from_headers(strheader): """Parse cookie data from a string in HTTP header (RFC 2616) format. @return: list of cookies @raises: ValueError for incomplete or invalid data """ res = [] headers = email.message_from_string(strheader) if "Host" not in headers: raise ValueError("Required header 'Host:' missing") host = headers["Host"] # XXX: our --help says we also pay attention to the Scheme: header, # but we don't?! path = headers.get("Path", "/") for headervalue in headers.get_all("Set-Cookie"): for pairs in split_header_words([headervalue]): for name, value in pairs: cookie = requests.cookies.create_cookie( name, value, domain=host, path=path ) res.append(cookie) return res linkchecker-10.5.0/linkcheck/data/000077500000000000000000000000001466565367000167455ustar00rootroot00000000000000linkchecker-10.5.0/linkcheck/data/__init__.py000066400000000000000000000000001466565367000210440ustar00rootroot00000000000000linkchecker-10.5.0/linkcheck/data/linkcheckerrc000066400000000000000000000220411466565367000214760ustar00rootroot00000000000000# Sample configuration file; see the linkcheckerrc(5) man page or # execute linkchecker -h for help on these options. # Commandline options override these settings. ##################### output configuration ########################## [output] # enable debug messages; see 'linkchecker -h' for valid debug names, example: #debug=all # print status output #status=1 # change the logging type #log=text # turn on/off --verbose #verbose=0 # turn on/off --warnings #warnings=1 # turn on/off --quiet #quiet=0 # additional file output, example: #fileoutput = text, html, gml, sql # errors to ignore (URL regular expression, message regular expression) #ignoreerrors= # ignore all errors for broken.example.com: # ^https?://broken.example.com/ # ignore SSL errors for dev.example.com: # ^https://dev.example.com/ ^SSLError ##################### logger configuration ########################## # logger output part names: # all For all parts # realurl The full url link # result Valid or invalid, with messages # extern 1 or 0, only in some logger types reported # base # name name and name # parenturl The referrer URL if there is any # info Some additional info, e.g. FTP welcome messages # warning Warnings # dltime Download time # checktime Check time # url The original url name, can be relative # intro The blurb at the beginning, "starting at ..." # outro The blurb at the end, "found x errors ..." # stats Statistics including URL lengths and contents. # each Logger can have separate configuration parameters # standard text logger [text] #filename=linkchecker-out.txt #parts=all #wraplength=65 # colors for the various parts, syntax is or ; # type can be bold, light, blink, invert # color can be default, black, red, green, yellow, blue, purple, cyan, white, # Black, Red, Green, Yellow, Blue, Purple, Cyan, White #colorparent=default #colorurl=default #colorname=default #colorreal=cyan #colorbase=purple #colorvalid=bold;green #colorinvalid=bold;red #colorinfo=default #colorwarning=bold;yellow #colordltime=default #colorreset=default # GML logger [gml] #filename=linkchecker-out.gml #parts=all # valid encodings are listed in http://docs.python.org/library/codecs.html#standard-encodings # example: #encoding=utf_16 # DOT logger [dot] #filename=linkchecker-out.dot #parts=all # default encoding is ascii since the original DOT format does not # support other charsets, example: #encoding=iso-8859-15 # CSV logger [csv] #filename=linkchecker-out.csv #separator=; #quotechar=" #dialect=excel #parts=all # SQL logger [sql] #filename=linkchecker-out.sql #dbname=linksdb #separator=; #parts=all # HTML logger [html] #filename=linkchecker-out.html # colors for the various parts #colorbackground=#fff7e5 #colorurl=#dcd5cf #colorborder=#000000 #colorlink=#191c83 #colorwarning=#e0954e #colorerror=#db4930 #colorok=#3ba557 #parts=all # failures logger [failures] #filename=$XDG_DATA_HOME/linkchecker/failures # custom xml logger [xml] #filename=linkchecker-out.xml # system encoding is used by default. Example: #encoding=iso-8859-1 # GraphXML logger [gxml] #filename=linkchecker-out.gxml # system encoding is used by default. Example: #encoding=iso-8859-1 # Sitemap logger [sitemap] #filename=linkchecker-out.sitemap.xml #encoding=utf-8 #priority=0.5 #frequency=daily ##################### checking options ########################## [checking] # number of threads #threads=10 # connection timeout in seconds #timeout=60 # Time to wait for checks to finish after the user aborts the first time # (with Ctrl-C or the abort button). #aborttimeout=300 # The recursion level determines how many times links inside pages are followed. #recursionlevel=-1 # parse a cookiefile for initial cookie data, example: #cookiefile=/path/to/cookies.txt # User-Agent header string to send to HTTP web servers # Note that robots.txt are always checked with the original User-Agent. Example: #useragent=Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) # When checking finishes, write a memory dump to a temporary file. # The memory dump is written both when checking finishes normally # and when checking gets canceled. # The memory dump only works if the python-meliae package is installed. # Otherwise a warning is printed to install it. #debugmemory=0 # When checking absolute URLs inside local files, the given root directory # is used as base URL. # Note that the given directory must have URL syntax, so it must use a slash # to join directories instead of a backslash. # And the given directory must end with a slash. # Unix example: #localwebroot=/var/www/ # Windows example: #localwebroot=/C|/public_html/ # Check SSL certificates. Set to an absolute pathname for a custom # CA cert bundle to use. Set to zero to disable SSL certificate verification. #sslverify=1 # Stop checking new URLs after the given number of seconds. Same as if the # user hits Ctrl-C after X seconds. Example: #maxrunseconds=600 # Don't download files larger than the given number of bytes #maxfilesizedownload=5242880 # Don't parse files larger than the given number of bytes #maxfilesizeparse=1048576 # Maximum number of URLs to check. New URLs will not be queued after the # given number of URLs is checked. Example: #maxnumurls=153 # Maximum number of requests per second to one host. #maxrequestspersecond=10 # Respect the instructions in any robots.txt files #robotstxt=1 # Allowed URL schemes as a comma-separated list. Example: #allowedschemes=http,https # Size of the result cache. Checking more urls might increase memory usage during runtime #resultcachesize=100000 ##################### filtering options ########################## [filtering] #ignore= # ignore everything with 'lconline' in the URL name # lconline # and ignore everything with 'bookmark' in the URL name # bookmark # and ignore all mailto: URLs # ^mailto: # do not recurse into the following URLs #nofollow= # just an example # http://www\.example\.com/bla # Ignore specified warnings (see linkchecker -h for the list of # recognized warnings). Add a comma-separated list of warnings here # that prevent a valid URL from being logged. Note that the warning # will be logged for invalid URLs. Example: #ignorewarnings=url-unicode-domain # Regular expression to add more URLs recognized as internal links. # Default is that URLs given on the command line are internal. #internlinks=^http://www\.example\.net/ # Check external links #checkextern=0 ##################### password authentication ########################## [authentication] # WARNING: if you store passwords in this configuration entry, make sure the # configuration file is not readable by other users. # Different user/password pairs for different URLs can be provided. # Entries are a triple (URL regular expression, username, password), # separated by whitespace. # If the regular expression matches, the given user/password pair is used # for authentication. The commandline options -u,-p match every link # and therefore override the entries given here. The first match wins. # At the moment, authentication is used for http[s] and ftp links. #entry= # Note that passwords are optional. If any passwords are stored here, # this file should not readable by other users. # ^https?://www\.example\.com/~calvin/ calvin mypass # ^ftp://www\.example\.com/secret/ calvin # if the website requires a login via a page with an HTML form the URL of the # page and optionally the username and password input element name attributes # can be provided. #loginurl=http://www.example.com/ # The name attributes of the username and password HTML input elements #loginuserfield=login #loginpasswordfield=password # Optionally the name attributes of any additional input elements and the values # to populate them with. Note that these are submitted without checking # whether matching input elements exist in the HTML form. Example: #loginextrafields= # name1:value1 # name 2:value 2 ############################ Plugins ################################### # # uncomment sections to enable plugins # Check HTML anchors #[AnchorCheck] # Print HTTP header info #[HttpHeaderInfo] # Comma separated list of header prefixes to print. # The names are case insensitive. # The default list is empty, so it should be non-empty when activating # this plugin. Example: #prefixes=Server,X- # Add country info to URLs #[LocationInfo] # Run W3C syntax checks #[CssSyntaxCheck] #[HtmlSyntaxCheck] # Search for regular expression in page contents #[RegexCheck] # Example: #warningregex=Oracle Error # Search for viruses in page contents #[VirusCheck] #clamavconf=/etc/clamav/clamd.conf # Check that SSL certificates have at least the given number of days validity. #[SslCertificateCheck] #sslcertwarndays=30 # Parse and check links in PDF files #[PdfParser] # Parse and check links in Word files #[WordParser] # Parse and check links in Markdown files. # Supported links are: # # [name](http://link.com "Optional title") # [id]: http://link.com "Optional title" #[MarkdownCheck] # Regexp of filename #filename_re=.*\.(markdown|md(own)?|mkdn?)$ linkchecker-10.5.0/linkcheck/decorators.py000066400000000000000000000123571466565367000205630ustar00rootroot00000000000000# Copyright (C) 2005-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Simple decorators (usable in Python >= 2.4). Example:: @synchronized(thread.allocate_lock()) def f(): "Synchronized function" print("i am synchronized:", f, f.__doc__) @deprecated def g(): "this function is deprecated" pass @notimplemented def h(): "todo" pass """ import warnings import signal import os import sys import time def update_func_meta(fake_func, real_func): """Set meta information (eg. __doc__) of fake function to that of the real function. @return fake_func """ fake_func.__module__ = real_func.__module__ fake_func.__name__ = real_func.__name__ fake_func.__doc__ = real_func.__doc__ fake_func.__dict__.update(real_func.__dict__) return fake_func def deprecated(func): """A decorator which can be used to mark functions as deprecated. It emits a warning when the function is called.""" def newfunc(*args, **kwargs): """Print deprecated warning and execute original function.""" warnings.warn( "Call to deprecated function %s." % func.__name__, category=DeprecationWarning, ) return func(*args, **kwargs) return update_func_meta(newfunc, func) def signal_handler(signal_number): """From http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/410666 A decorator to set the specified function as handler for a signal. This function is the 'outer' decorator, called with only the (non-function) arguments. If signal_number is not a valid signal (for example signal.SIGN), no handler is set. """ # create the 'real' decorator which takes only a function as an argument def newfunc(function): """Register function as signal handler.""" # note: actually the kill(2) function uses the signal number of 0 # for a special case, but for signal(2) only positive integers # are allowed is_valid_signal = 0 < signal_number < signal.NSIG if is_valid_signal and os.name == 'posix': signal.signal(signal_number, function) return function return newfunc def synchronize(lock, func, log_duration_secs=0): """Return synchronized function acquiring the given lock.""" def newfunc(*args, **kwargs): """Execute function synchronized.""" t = time.time() with lock: duration = time.time() - t if duration > log_duration_secs > 0: print( "WARN:", func.__name__, "locking took %0.2f seconds" % duration, file=sys.stderr, ) return func(*args, **kwargs) return update_func_meta(newfunc, func) def synchronized(lock): """A decorator calling a function with acquired lock.""" return lambda func: synchronize(lock, func) def notimplemented(func): """Raises a NotImplementedError if the function is called.""" def newfunc(*args, **kwargs): """Raise NotImplementedError""" co = func.func_code attrs = (co.co_name, co.co_filename, co.co_firstlineno) raise NotImplementedError("function %s at %s:%d is not implemented" % attrs) return update_func_meta(newfunc, func) def timeit(func, log, limit): """Print execution time of the function. For quick'n'dirty profiling.""" def newfunc(*args, **kwargs): """Execute function and print execution time.""" t = time.time() res = func(*args, **kwargs) duration = time.time() - t if duration > limit: print(func.__name__, "took %0.2f seconds" % duration, file=log) print(args, file=log) print(kwargs, file=log) return res return update_func_meta(newfunc, func) def timed(log=sys.stderr, limit=2.0): """Decorator to run a function with timing info.""" return lambda func: timeit(func, log, limit) class curried: """Decorator that returns a function that keeps returning functions until all arguments are supplied; then the original function is evaluated.""" def __init__(self, func, *a): """Store function and arguments.""" self.func = func self.args = a def __call__(self, *a): """If all arguments function arguments are supplied, call it. Else return another curried object.""" args = self.args + a if len(args) < self.func.func_code.co_argcount: return curried(self.func, *args) else: return self.func(*args) linkchecker-10.5.0/linkcheck/director/000077500000000000000000000000001466565367000176475ustar00rootroot00000000000000linkchecker-10.5.0/linkcheck/director/__init__.py000066400000000000000000000110771466565367000217660ustar00rootroot00000000000000# Copyright (C) 2006-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Management of checking a queue of links with several threads. """ import os import time from .. import log, LOG_CHECK, LinkCheckerError, LinkCheckerInterrupt, plugins from ..cache import urlqueue, robots_txt, results from . import aggregator, console def check_urls(aggregate): """Main check function; checks all configured URLs until interrupted with Ctrl-C. @return: None """ try: aggregate.visit_loginurl() except LinkCheckerError as msg: log.warn(LOG_CHECK, _("Problem using login URL: %(msg)s.") % dict(msg=msg)) return except Exception as msg: log.warn(LOG_CHECK, _("Error using login URL: %(msg)s.") % dict(msg=msg)) raise try: aggregate.logger.start_log_output() except Exception as msg: log.error(LOG_CHECK, _("Error starting log output: %(msg)s.") % dict(msg=msg)) raise try: if not aggregate.urlqueue.empty(): aggregate.start_threads() check_url(aggregate) aggregate.finish() aggregate.end_log_output() except LinkCheckerInterrupt: raise except KeyboardInterrupt: interrupt(aggregate) except RuntimeError: log.warn( LOG_CHECK, _( "Could not start a new thread. Check that the current user" " is allowed to start new threads." ), ) abort(aggregate) except Exception: # Catching "Exception" is intentionally done. This saves the program # from libraries that raise all kinds of strange exceptions. console.internal_error() aggregate.logger.log_internal_error() abort(aggregate) # Not caught exceptions at this point are SystemExit and GeneratorExit, # and both should be handled by the calling layer. def check_url(aggregate): """Helper function waiting for URL queue.""" while True: try: aggregate.urlqueue.join(timeout=30) break except urlqueue.Timeout: # Cleanup threads every 30 seconds aggregate.remove_stopped_threads() if not any(aggregate.get_check_threads()): break def interrupt(aggregate): """Interrupt execution and shutdown, ignoring any subsequent interrupts.""" while True: try: log.warn(LOG_CHECK, _("interrupt; waiting for active threads to finish")) log.warn(LOG_CHECK, _("another interrupt will exit immediately")) abort(aggregate) break except KeyboardInterrupt: pass def abort(aggregate): """Helper function to ensure a clean shutdown.""" while True: try: aggregate.abort() aggregate.finish() aggregate.end_log_output(interrupt=True) break except KeyboardInterrupt: log.warn(LOG_CHECK, _("user abort; force shutdown")) aggregate.end_log_output(interrupt=True) abort_now() def abort_now(): """Force exit of current process without cleanup.""" if os.name == 'posix': # Unix systems can use signals import signal os.kill(os.getpid(), signal.SIGTERM) time.sleep(1) os.kill(os.getpid(), signal.SIGKILL) elif os.name == 'nt': # NT has os.abort() os.abort() else: # All other systems have os._exit() as best shot. os._exit(3) def get_aggregate(config): """Get an aggregator instance with given configuration.""" _urlqueue = urlqueue.UrlQueue(max_allowed_urls=config["maxnumurls"]) _robots_txt = robots_txt.RobotsTxt(config["useragent"]) plugin_manager = plugins.PluginManager(config) result_cache = results.ResultCache(config["resultcachesize"]) return aggregator.Aggregate( config, _urlqueue, _robots_txt, plugin_manager, result_cache ) linkchecker-10.5.0/linkcheck/director/aggregator.py000066400000000000000000000230331466565367000223440ustar00rootroot00000000000000# Copyright (C) 2006-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Aggregate needed object instances for checker threads. """ import threading import requests import time import urllib.parse import random from .. import log, LOG_CHECK, strformat, LinkCheckerError from ..decorators import synchronized from ..cache import urlqueue from ..htmlutil import loginformsearch from ..cookies import from_file from . import logger, status, checker, interrupter _threads_lock = threading.RLock() _hosts_lock = threading.RLock() _downloadedbytes_lock = threading.RLock() def new_request_session(config, cookies): """Create a new request session.""" session = requests.Session() if cookies: session.cookies = cookies session.max_redirects = config["maxhttpredirects"] session.headers.update( {"User-Agent": config["useragent"]} ) if config["cookiefile"]: try: for cookie in from_file(config["cookiefile"]): session.cookies.set_cookie(cookie) except Exception as msg: log.error( LOG_CHECK, _("Could not parse cookie file: %s. %s"), config["cookiefile"], msg ) return session class Aggregate: """Store thread-safe data collections for checker threads.""" wait_time_min_default = 0.1 wait_time_max_default = 0.6 def __init__(self, config, urlqueue, robots_txt, plugin_manager, result_cache): """Store given link checking objects.""" self.config = config self.urlqueue = urlqueue self.logger = logger.Logger(config) self.threads = [] self.request_sessions = {} self.robots_txt = robots_txt self.plugin_manager = plugin_manager self.result_cache = result_cache self.times = {} self.maxrated = {} self.cookies = None requests_per_second = config["maxrequestspersecond"] self.wait_time_min = 1.0 / requests_per_second self.wait_time_max = 6 * self.wait_time_min self.downloaded_bytes = 0 def visit_loginurl(self): """Check for a login URL and visit it.""" url = self.config["loginurl"] if not url: return user, password = self.config.get_user_password(url) if not user and not password: raise LinkCheckerError( "loginurl is configured but neither user nor password are set" ) session = new_request_session(self.config, self.cookies) log.debug(LOG_CHECK, "Getting login form %s", url) kwargs = dict(timeout=self.config["timeout"]) # XXX: sslverify? can we reuse HttpUrl.get_request_kwargs() # somehow? response = session.get(url, **kwargs) response.raise_for_status() cgiuser = self.config["loginuserfield"] if user else None cgipassword = self.config["loginpasswordfield"] if password else None form = loginformsearch.search_form(response.text, cgiuser, cgipassword) if not form: raise LinkCheckerError("Login form not found at %s" % url) if user: form.data[cgiuser] = user if password: form.data[cgipassword] = password for key, value in self.config["loginextrafields"].items(): form.data[key] = value formurl = urllib.parse.urljoin(url, form.url) log.debug(LOG_CHECK, "Posting login data to %s", formurl) response = session.post(formurl, data=form.data, **kwargs) response.raise_for_status() self.cookies = session.cookies if len(self.cookies) == 0: raise LinkCheckerError("No cookies set by login URL %s" % url) @synchronized(_threads_lock) def start_threads(self): """Spawn threads for URL checking and status printing.""" if self.config["status"]: t = status.Status(self, self.config["status_wait_seconds"]) t.start() self.threads.append(t) if self.config["maxrunseconds"]: t = interrupter.Interrupt(self.config["maxrunseconds"]) t.start() self.threads.append(t) num = self.config["threads"] if num > 0: for dummy in range(num): t = checker.Checker( self.urlqueue, self.logger, self.add_request_session ) self.threads.append(t) t.start() else: self.request_sessions[threading.get_ident()] = new_request_session( self.config, self.cookies ) checker.check_urls(self.urlqueue, self.logger) @synchronized(_threads_lock) def add_request_session(self): """Add a request session for current thread.""" session = new_request_session(self.config, self.cookies) self.request_sessions[threading.get_ident()] = session @synchronized(_threads_lock) def get_request_session(self): """Get the request session for current thread.""" return self.request_sessions[threading.get_ident()] @synchronized(_hosts_lock) def wait_for_host(self, host): """Throttle requests to one host.""" t = time.time() if host in self.times: due_time = self.times[host] if due_time > t: wait = due_time - t time.sleep(wait) t = time.time() if host in self.maxrated: wait_time_min, wait_time_max = self.wait_time_min, self.wait_time_max else: wait_time_min = max(self.wait_time_min, self.wait_time_min_default) wait_time_max = max(self.wait_time_max, self.wait_time_max_default) log.debug(LOG_CHECK, "Min wait time: %s Max wait time: %s for host: %s", wait_time_min, wait_time_max, host) wait_time = random.uniform(wait_time_min, wait_time_max) self.times[host] = t + wait_time @synchronized(_hosts_lock) def set_maxrated_for_host(self, host): """Remove the limit on the maximum request rate for a host.""" self.maxrated[host] = True @synchronized(_threads_lock) def print_active_threads(self): """Log all currently active threads.""" debug = log.is_debug(LOG_CHECK) if debug: first = True for name in self.get_check_threads(): if first: log.info(LOG_CHECK, _("These URLs are still active:")) first = False log.info(LOG_CHECK, name[12:]) args = dict( num=len( [x for x in self.threads if x.name.startswith("CheckThread-")] ), timeout=strformat.strduration_long(self.config["aborttimeout"]), ) log.info( LOG_CHECK, _( "%(num)d URLs are still active. After a timeout of %(timeout)s" " the active URLs will stop." ) % args, ) @synchronized(_threads_lock) def get_check_threads(self): """Return iterator of checker threads.""" for t in self.threads: if t.name.startswith("CheckThread-"): yield t.name def cancel(self): """Empty the URL queue.""" self.urlqueue.do_shutdown() def abort(self): """Print still-active URLs and empty the URL queue.""" self.print_active_threads() self.cancel() timeout = self.config["aborttimeout"] try: self.urlqueue.join(timeout=timeout) except urlqueue.Timeout: log.warn( LOG_CHECK, "Abort timed out after %d seconds, stopping application." % timeout, ) raise KeyboardInterrupt() @synchronized(_threads_lock) def remove_stopped_threads(self): """Remove the stopped threads from the internal thread list.""" self.threads = [t for t in self.threads if t.is_alive()] @synchronized(_threads_lock) def finish(self): """Wait for checker threads to finish.""" if not self.urlqueue.empty(): # This happens when all checker threads died. self.cancel() for t in self.threads: t.stop() for t in self.threads: t.join(timeout=1.0) @synchronized(_threads_lock) def is_finished(self): """Determine if checking is finished.""" self.remove_stopped_threads() return self.urlqueue.empty() and not self.threads @synchronized(_downloadedbytes_lock) def add_downloaded_bytes(self, numbytes): """Add to number of downloaded bytes.""" self.downloaded_bytes += numbytes def end_log_output(self, **kwargs): """Print ending output to log.""" kwargs.update( dict( downloaded_bytes=self.downloaded_bytes, num_urls=len(self.result_cache), ) ) self.logger.end_log_output(**kwargs) linkchecker-10.5.0/linkcheck/director/checker.py000066400000000000000000000077761466565367000216460ustar00rootroot00000000000000# Copyright (C) 2006-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ URL checking functions. """ import copy import time from . import task from ..cache import urlqueue from .. import parser # Interval in which each check thread looks if it's stopped. QUEUE_POLL_INTERVALL_SECS = 1.0 def check_urls(urlqueue, logger): """Check URLs without threading.""" while not urlqueue.empty(): url_data = urlqueue.get() try: check_url(url_data, logger) finally: urlqueue.task_done(url_data) def check_url(url_data, logger): """Check a single URL with logging.""" if url_data.has_result: logger.log_url(url_data.to_wire()) else: cache = url_data.aggregate.result_cache key = url_data.cache_url result = cache.get_result(key) if result is None: # check check_start = time.time() try: url_data.check() do_parse = url_data.check_content() url_data.checktime = time.time() - check_start # Add result to cache result = url_data.to_wire() cache.add_result(key, result) for alias in url_data.aliases: # redirect aliases cache.add_result(alias, result) logger.log_url(result) # parse content recursively # XXX this could add new warnings which should be cached. if do_parse: parser.parse_url(url_data) finally: # close/release possible open connection url_data.close_connection() else: # copy data from cache and adjust it result = copy.copy(result) result.parent_url = url_data.parent_url result.base_ref = url_data.base_ref or "" result.base_url = url_data.base_url or "" result.line = url_data.line result.column = url_data.column result.level = url_data.recursion_level result.name = url_data.name logger.log_url(result) class Checker(task.LoggedCheckedTask): """URL check thread.""" def __init__(self, urlqueue, logger, add_request_session): """Store URL queue and logger.""" super().__init__(logger) self.urlqueue = urlqueue self.origname = self.name self.add_request_session = add_request_session def run_checked(self): """Check URLs in the queue.""" # construct per-thread HTTP/S requests session self.add_request_session() while not self.stopped(0): self.check_url() def check_url(self): """Try to get URL data from queue and check it.""" try: url_data = self.urlqueue.get(timeout=QUEUE_POLL_INTERVALL_SECS) if url_data is not None: try: self.check_url_data(url_data) finally: self.urlqueue.task_done(url_data) self.name = self.origname except urlqueue.Empty: pass except Exception: self.internal_error() def check_url_data(self, url_data): """Check one URL data instance.""" self.name = "CheckThread-%s" % (url_data.url or "") check_url(url_data, self.logger) linkchecker-10.5.0/linkcheck/director/console.py000066400000000000000000000122241466565367000216640ustar00rootroot00000000000000# Copyright (C) 2006-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Helpers for console output. """ import sys import os import time from .. import i18n, configuration, strformat, better_exchook2 # Output to stdout and stderr, encoded with the default encoding stderr = i18n.get_encoded_writer(out=sys.stderr) stdout = i18n.get_encoded_writer() class StatusLogger: """Standard status logger. Default output is stderr.""" def __init__(self, fd=stderr): """Save file descriptor for logging.""" self.fd = fd def log_status(self, checked, in_progress, queue, duration, num_urls): """Write status message to file descriptor.""" msg = _n("%2d thread active", "%2d threads active", in_progress) % in_progress self.write("%s, " % msg) msg = _n("%5d link queued", "%5d links queued", queue) % queue self.write("%s, " % msg) msg = _n("%4d link", "%4d links", checked) % checked self.write("%s" % msg) msg = _n("%3d URL", "%3d URLs", num_urls) % num_urls self.write(" in %s checked, " % msg) msg = _("runtime %s") % strformat.strduration_long(duration) self.writeln(msg) self.flush() def write(self, msg): """Write message to file descriptor.""" self.fd.write(msg) def writeln(self, msg): """Write status message and line break to file descriptor.""" self.fd.write(f"{msg}{os.linesep}") def flush(self): """Flush file descriptor.""" self.fd.flush() def internal_error(out=stderr, etype=None, evalue=None, tb=None): """Print internal error message (output defaults to stderr).""" print(os.linesep, file=out) print(_("""********** Oops, I did it again. ************* You have found an internal error in LinkChecker. Please write a bug report at %s and include the following information: - the URL or file you are testing - the system information below When using the commandline client: - your commandline arguments and any custom configuration files. - the output of a debug run with option "-Dall" Not disclosing some of the information above due to privacy reasons is ok. I will try to help you nonetheless, but you have to give me something I can work with ;) . """) % configuration.SupportUrl, file=out) if etype is None: etype = sys.exc_info()[0] if evalue is None: evalue = sys.exc_info()[1] if tb is None: tb = sys.exc_info()[2] better_exchook2.better_exchook(etype, evalue, tb, out=out) print_app_info(out=out) print_proxy_info(out=out) print_locale_info(out=out) print( os.linesep, _("******** LinkChecker internal error, over and out ********"), file=out, ) def print_env_info(key, out=stderr): """If given environment key is defined, print it out.""" value = os.getenv(key) if value is not None: print(key, "=", repr(value), file=out) def print_proxy_info(out=stderr): """Print proxy info.""" for key in ("http_proxy", "https_proxy", "curl_ca_bundle", "no_proxy"): print_env_info(key, out=out) def print_locale_info(out=stderr): """Print locale info.""" for key in ("LANGUAGE", "LC_ALL", "LC_CTYPE", "LANG"): print_env_info(key, out=out) # Environment variables influencing the interpreter execution # See python(1) man page. PYTHON_ENV_VARS = ( 'PYTHONHOME', 'PYTHONPATH', 'PYTHONSTARTUP', 'PYTHONY2K', 'PYTHONOPTIMIZE', 'PYTHONDEBUG', 'PYTHONDONTWRITEBYTECODE', 'PYTHONINSPECT', 'PYTHONIOENCODING', 'PYTHONNOUSERSITE', 'PYTHONUNBUFFERED', 'PYTHONVERBOSE', 'PYTHONWARNINGS', 'PYTHONHASHSEED', ) def print_app_info(out=stderr): """Print system and application info (output defaults to stderr).""" print(_("System info:"), file=out) print(configuration.App, file=out) print(_("Released on:"), configuration.ReleaseDate, file=out) print( _("Python %(version)s on %(platform)s") % {"version": sys.version, "platform": sys.platform}, file=out, ) for key in PYTHON_ENV_VARS: print_env_info(key, out=out) print(configuration.get_modules_info(), file=out) stime = strformat.strtime(time.time()) print(_("Local time:"), stime, file=out) print(_("sys.argv:"), sys.argv, file=out) def print_version(out=stdout): """Print the program version (output defaults to stdout).""" print(configuration.App, _("released"), configuration.ReleaseDate, file=out) print(configuration.Copyright, file=out) linkchecker-10.5.0/linkcheck/director/interrupter.py000066400000000000000000000034461466565367000226130ustar00rootroot00000000000000# Copyright (C) 2006-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """Status message handling""" import time from . import task from .. import log, LOG_CHECK, strformat class Interrupt(task.CheckedTask): """Thread that raises KeyboardInterrupt after a specified duration. This gives us a portable SIGALRM implementation. The duration is checked every 5 seconds. """ WaitSeconds = 5 def __init__(self, duration): """Initialize the task. @param duration: raise KeyboardInterrupt after given number of seconds @type duration: int """ super().__init__() self.duration = duration def run_checked(self): """Wait and raise KeyboardInterrupt after.""" self.start_time = time.time() self.name = "Interrupt" while not self.stopped(self.WaitSeconds): duration = time.time() - self.start_time if duration > self.duration: log.warn( LOG_CHECK, "Interrupt after %s" % strformat.strduration_long(duration), ) raise KeyboardInterrupt() linkchecker-10.5.0/linkcheck/director/logger.py000066400000000000000000000051461466565367000215060ustar00rootroot00000000000000# Copyright (C) 2006-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """Logger for aggregator instances""" import threading import _thread from ..decorators import synchronized _lock = threading.Lock() class Logger: """Thread safe multi-logger class used by aggregator instances.""" def __init__(self, config): """Initialize basic logging variables.""" self.loggers = [config['logger']] self.loggers.extend(config['fileoutput']) self.verbose = config["verbose"] self.warnings = config["warnings"] def start_log_output(self): """ Start output of all configured loggers. """ for logger in self.loggers: logger.start_output() def end_log_output(self, **kwargs): """ End output of all configured loggers. """ for logger in self.loggers: logger.end_output(**kwargs) def do_print(self, url_data): """Determine if URL entry should be logged or not.""" if self.verbose: return True if self.warnings and url_data.warnings: return True return not url_data.valid @synchronized(_lock) def log_url(self, url_data): """Send new url to all configured loggers.""" self.check_active_loggers() do_print = self.do_print(url_data) # Only send a transport object to the loggers, not the complete # object instance. for log in self.loggers: log.log_filter_url(url_data, do_print) @synchronized(_lock) def log_internal_error(self): """Document that an internal error occurred.""" for logger in self.loggers: logger.log_internal_error() def check_active_loggers(self): """Check if all loggers are deactivated due to I/O errors.""" for logger in self.loggers: if logger.is_active: break else: _thread.interrupt_main() linkchecker-10.5.0/linkcheck/director/status.py000066400000000000000000000043111466565367000215430ustar00rootroot00000000000000# Copyright (C) 2006-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """Status message handling""" import time from . import task class Status(task.LoggedCheckedTask): """Thread that gathers and logs the status periodically.""" def __init__(self, aggregator, wait_seconds): """Initialize the status logger task. @param urlqueue: the URL queue @type urlqueue: Urlqueue @param logger: the logger object to inform about status @type logger: console.StatusLogger @param wait_seconds: interval in seconds to report status @type wait_seconds: int """ logger = aggregator.config.status_logger super().__init__(logger) self.aggregator = aggregator self.wait_seconds = wait_seconds assert self.wait_seconds >= 1 def run_checked(self): """Print periodic status messages.""" self.start_time = time.time() self.name = "Status" # the first status should be after a second wait_seconds = 1 first_wait = True while not self.stopped(wait_seconds): self.log_status() if first_wait: wait_seconds = self.wait_seconds first_wait = False def log_status(self): """Log a status message.""" duration = time.time() - self.start_time checked, in_progress, queue = self.aggregator.urlqueue.status() num_urls = len(self.aggregator.result_cache) self.logger.log_status(checked, in_progress, queue, duration, num_urls) linkchecker-10.5.0/linkcheck/director/task.py000066400000000000000000000035111466565367000211630ustar00rootroot00000000000000# Copyright (C) 2006-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. import _thread from ..decorators import notimplemented from .. import threader from . import console class CheckedTask(threader.StoppableThread): """Stoppable URL check task, handling error conditions while running.""" def run(self): """Handle keyboard interrupt and other errors.""" try: self.run_checked() except KeyboardInterrupt: _thread.interrupt_main() except Exception: self.internal_error() @notimplemented def run_checked(self): """Overload in subclass.""" pass @notimplemented def internal_error(self): """Overload in subclass.""" pass class LoggedCheckedTask(CheckedTask): """URL check task with a logger instance and internal error handling.""" def __init__(self, logger): """Initialize super instance and store given logger.""" super().__init__() self.logger = logger def internal_error(self): """Log an internal error on console and the logger.""" console.internal_error() self.logger.log_internal_error() linkchecker-10.5.0/linkcheck/dummy.py000066400000000000000000000037021466565367000175430ustar00rootroot00000000000000# Copyright (C) 2005-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Dummy objects. """ class Dummy: """A dummy object ignores all access to it. Useful for testing.""" def __init__(self, *args, **kwargs): """Return None""" pass def __call__(self, *args, **kwargs): """Return self.""" return self def __getattr__(self, name): """Return self.""" return self def __setattr__(self, name, value): """Return None""" pass def __delattr__(self, name): """Return None""" pass def __str__(self): """Return 'dummy'""" return "dummy" def __repr__(self): """Return ''""" return "" def __unicode__(self): """Return 'dummy'""" return "dummy" def __len__(self): """Return zero""" return 0 def __getitem__(self, key): """Return self""" return self def __setitem__(self, key, value): """Return None""" pass def __delitem__(self, key): """Return None""" pass def __contains__(self, key): """Return False""" return False def dummy(*args, **kwargs): """Ignore any positional or keyword arguments, return None.""" pass linkchecker-10.5.0/linkcheck/fileutil.py000066400000000000000000000063751466565367000202360ustar00rootroot00000000000000# Copyright (C) 2005-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ File and path utilities. """ import os import locale import stat import tempfile import importlib from functools import lru_cache def has_module(name, without_error=True): """Test if given module can be imported. @param without_error: True if module must not throw any errors when importing @return: flag if import is successful @rtype: bool """ try: importlib.import_module(name) return True except ImportError: return False except Exception: # some modules raise errors when intitializing return not without_error def get_mtime(filename): """Return modification time of filename or zero on errors.""" try: return os.path.getmtime(filename) except OSError: return 0 def get_size(filename): """Return file size in Bytes, or -1 on error.""" try: return os.path.getsize(filename) except OSError: return -1 # http://developer.gnome.org/doc/API/2.0/glib/glib-running.html if "G_FILENAME_ENCODING" in os.environ: FSCODING = os.environ["G_FILENAME_ENCODING"].split(",")[0] if FSCODING == "@locale": FSCODING = locale.getpreferredencoding() elif "G_BROKEN_FILENAMES" in os.environ: FSCODING = locale.getpreferredencoding() else: FSCODING = "utf-8" def path_safe(path): """Ensure path string is compatible with the platform file system encoding.""" if path and not os.path.supports_unicode_filenames: path = path.encode(FSCODING, "replace").decode(FSCODING) return path def get_temp_file(mode='r', **kwargs): """Return tuple (open file object, filename) pointing to a temporary file.""" fd, filename = tempfile.mkstemp(**kwargs) return os.fdopen(fd, mode), filename def is_tty(fp): """Check if is a file object pointing to a TTY.""" return hasattr(fp, "isatty") and fp.isatty() @lru_cache(128) def is_readable(filename): """Check if file is readable.""" return os.access(filename, os.R_OK) def is_accessable_by_others(filename): """Check if file is group or world accessible.""" mode = os.stat(filename)[stat.ST_MODE] return mode & (stat.S_IRWXG | stat.S_IRWXO) def is_writable_by_others(filename): """Check if file or directory is world writable.""" mode = os.stat(filename)[stat.ST_MODE] return mode & stat.S_IWOTH def is_valid_config_source(filename): """Check if the file is a valid config file.""" return os.path.exists(filename) and ( os.path.isfile(filename) or stat.S_ISFIFO(os.stat(filename).st_mode)) linkchecker-10.5.0/linkcheck/ftpparse.py000066400000000000000000000123611466565367000202350ustar00rootroot00000000000000# Copyright (C) 2009-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Python implementation of a part of Dan Bernstein's ftpparse library. See also http://cr.yp.to/ftpparse.html """ months = ( "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec", ) def ismonth(txt): """Check if given text is a month name.""" return txt.lower() in months def ftpparse(line): """Parse a FTP list line into a dictionary with attributes: name - name of file (string) trycwd - False if cwd is definitely pointless, True otherwise tryretr - False if retr is definitely pointless, True otherwise If the line has no file information, None is returned """ if len(line) < 2: # an empty name in EPLF, with no info, could be 2 chars return None info = dict(name=None, trycwd=False, tryretr=False) # EPLF format # http://pobox.com/~djb/proto/eplf.html # "+i8388621.29609,m824255902,/,\tdev" # "+i8388621.44468,m839956783,r,s10376,\tRFCEPLF" if line[0] == '+': if '\t' in line: flags, name = line.split('\t', 1) info['name'] = name flags = flags.split(',') info['trycwd'] = '/' in flags info['tryretr'] = 'r' in flags return info # UNIX-style listing, without inum and without blocks # "-rw-r--r-- 1 root other 531 Jan 29 03:26 README" # "dr-xr-xr-x 2 root other 512 Apr 8 1994 etc" # "dr-xr-xr-x 2 root 512 Apr 8 1994 etc" # "lrwxrwxrwx 1 root other 7 Jan 25 00:17 bin -> usr/bin" # Also produced by Microsoft's FTP servers for Windows: # "---------- 1 owner group 1803128 Jul 10 10:18 ls-lR.Z" # "d--------- 1 owner group 0 May 9 19:45 Softlib" # Also WFTPD for MS-DOS: # "-rwxrwxrwx 1 noone nogroup 322 Aug 19 1996 message.ftp" # Also NetWare: # "d [R----F--] supervisor 512 Jan 16 18:53 login" # "- [R----F--] rhesus 214059 Oct 20 15:27 cx.exe" # Also NetPresenz for the Mac: # "-------r-- 326 1391972 1392298 Nov 22 1995 MegaPhone.sit" # "drwxrwxr-x folder 2 May 10 1996 network" if line[0] in 'bcdlps-': if line[0] == 'd': info['trycwd'] = True if line[0] == '-': info['tryretr'] = True if line[0] == 'l': info['trycwd'] = info['tryretr'] = True parts = line.split() if len(parts) < 7: return None del parts[0] # skip permissions if parts[0] != 'folder': del parts[0] # skip nlink del parts[0] # skip uid del parts[0] # skip gid or size if not ismonth(parts[0]): del parts[0] # skip size if not ismonth(parts[0]): return None del parts[0] # skip month del parts[0] # skip day if not parts: return None del parts[0] # skip year or time name = " ".join(parts) # resolve links if line[0] == 'l' and ' -> ' in name: name = name.split(' -> ', 1)[1] # eliminate extra NetWare spaces if line[1] in ' [' and name.startswith(' '): name = name[3:] info["name"] = name return info # MultiNet (some spaces removed from examples) # "00README.TXT;1 2 30-DEC-1996 17:44 [SYSTEM] (RWED,RWED,RE,RE)" # "CORE.DIR;1 1 8-SEP-1996 16:09 [SYSTEM] (RWE,RWE,RE,RE)" # and non-MutliNet VMS: # "CII-MANUAL.TEX;1 213/216 29-JAN-1996 03:33:12 [ANONYMOU,ANONYMOUS] (RWED,RWED,,)" i = line.find(';') if i != -1: name = line[:i] if name.endswith(".DIR"): name = name[:-4] info["trycwd"] = True else: info["tryretr"] = True info["name"] = name return info # MS-DOS format # 04-27-00 09:09PM licensed # 07-18-00 10:16AM pub # 04-14-00 03:47PM 589 readme.htm if line[0].isdigit(): parts = line.split() if len(parts) != 4: return None info['name'] = parts[3] if parts[2][0] == '<': info['trycwd'] = True else: info['tryretr'] = True return info # Some useless lines, safely ignored: # "Total of 11 Files, 10966 Blocks." (VMS) # "total 14786" (UNIX) # "DISK$ANONFTP:[ANONYMOUS]" (VMS) # "Directory DISK$PCSA:[ANONYM]" (VMS) return None linkchecker-10.5.0/linkcheck/htmlutil/000077500000000000000000000000001466565367000176765ustar00rootroot00000000000000linkchecker-10.5.0/linkcheck/htmlutil/__init__.py000066400000000000000000000014021466565367000220040ustar00rootroot00000000000000# Copyright (C) 2008-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ HTML utils """ linkchecker-10.5.0/linkcheck/htmlutil/htmlsoup.py000066400000000000000000000030061466565367000221220ustar00rootroot00000000000000# Copyright (C) 2000-2018 Petr Dlouhy # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ HTML parser implemented using Beautiful Soup and html.parser. """ import warnings warnings.filterwarnings( "ignore", message="The soupsieve package is not installed. CSS selectors cannot be used.", category=UserWarning, module="bs4", ) import bs4 # bs4 4.9.1 introduced MarkupResemblesLocatorWarning hasattr(bs4, "MarkupResemblesLocatorWarning") and warnings.simplefilter( 'ignore', bs4.MarkupResemblesLocatorWarning ) # bs4 4.11.0 introduced builder.XMLParsedAsHTMLWarning hasattr(bs4.builder, "XMLParsedAsHTMLWarning") and warnings.simplefilter( 'ignore', bs4.builder.XMLParsedAsHTMLWarning ) def make_soup(markup, from_encoding=None): return bs4.BeautifulSoup( markup, "html.parser", from_encoding=from_encoding, multi_valued_attributes=None ) linkchecker-10.5.0/linkcheck/htmlutil/linkparse.py000066400000000000000000000200561466565367000222430ustar00rootroot00000000000000# Copyright (C) 2001-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Find link tags in HTML text. """ import re from .srcsetparse import parse_srcset from .. import strformat, log, LOG_CHECK, url as urlutil unquote = strformat.unquote # HTML4/5 link tags # ripped mainly from HTML::Tagset.pm with HTML5 added LinkTags = { 'a': ['href'], 'applet': ['archive', 'src'], 'area': ['href'], 'audio': ['src'], # HTML5 'bgsound': ['src'], 'blockquote': ['cite'], 'body': ['background'], 'button': ['formaction'], # HTML5 'del': ['cite'], 'embed': ['pluginspage', 'src'], 'form': ['action'], 'frame': ['src', 'longdesc'], 'head': ['profile'], 'html': ['manifest'], # HTML5 'iframe': ['src', 'longdesc'], 'ilayer': ['background'], 'img': ['src', 'lowsrc', 'longdesc', 'usemap', 'srcset'], 'input': ['src', 'usemap', 'formaction'], 'ins': ['cite'], 'isindex': ['action'], 'layer': ['background', 'src'], 'link': ['href'], 'meta': ['content', 'href'], 'object': ['classid', 'data', 'archive', 'usemap', 'codebase'], 'q': ['cite'], 'script': ['src'], 'source': ['src'], # HTML5 'table': ['background'], 'td': ['background'], 'th': ['background'], 'tr': ['background'], 'track': ['src'], # HTML5 'video': ['src'], # HTML5 'xmp': ['href'], None: ['style', 'itemtype'], } # HTML anchor tags AnchorTags = { 'a': ['name'], None: ['id'], } # WML tags WmlTags = { 'a': ['href'], 'go': ['href'], 'img': ['src'], } # matcher for tags refresh_re = re.compile(r"(?i)^\d+;\s*url=(?P.+)$") _quoted_pat = r"('[^']+'|\"[^\"]+\"|[^\)\s]+)" css_url_re = re.compile(r"url\(\s*(?P%s)\s*\)" % _quoted_pat) # Note that swf_url_re, unlike all other regular expressions here, is meant # to match byte strings. Yes, we're scraping binary SWF data for anything # that looks like a URL. What did you expect, a full SWF format decoder? swf_url_re = re.compile(b"(?i)%s" % urlutil.safe_url_pattern.encode('ascii')) c_comment_re = re.compile(r"/\*.*?\*/", re.DOTALL) def strip_c_comments(text): """Remove C/CSS-style comments from text. Note that this method also deliberately removes comments inside of strings.""" return c_comment_re.sub('', text) def is_meta_url(attr, attrs): """Check if the meta attributes contain a URL.""" res = False if attr == "content": equiv = attrs.get('http-equiv', '').lower() scheme = attrs.get('scheme', '').lower() res = equiv in ('refresh',) or scheme in ('dcterms.uri',) if attr == "href": rel = attrs.get('rel', '').lower() res = rel in ('shortcut icon', 'icon') return res def is_form_get(attr, attrs): """Check if this is a GET form action URL.""" res = False if attr == "action": method = attrs.get('method', '').lower() res = method != 'post' return res class LinkFinder: """Find HTML links, and apply them to the callback function with the format (url, lineno, column, name, codebase).""" def __init__(self, callback, tags): """Store content in buffer and initialize URL list.""" self.callback = callback # set universal tag attributes using tagname None self.universal_attrs = set(tags.get(None, [])) self.tags = dict() for tag, attrs in tags.items(): self.tags[tag] = set(attrs) # add universal tag attributes self.tags[tag].update(self.universal_attrs) self.base_ref = '' def html_element(self, tag, attrs, element_text, lineno, column): """Search for links and store found URLs in a list.""" log.debug(LOG_CHECK, "LinkFinder tag %s attrs %s", tag, attrs) log.debug(LOG_CHECK, "line %d col %d", lineno, column) if tag == "base" and not self.base_ref: self.base_ref = attrs.get("href", '') tagattrs = self.tags.get(tag, self.universal_attrs) # parse URLs in tag (possibly multiple URLs in CSS styles) for attr in sorted(tagattrs.intersection(attrs)): if tag == "meta" and not is_meta_url(attr, attrs): continue if tag == "form" and not is_form_get(attr, attrs): continue # name of this link name = self.get_link_name(tag, attrs, attr, element_text) # possible codebase base = '' if tag == 'applet': base = attrs.get('codebase', '') if not base: base = self.base_ref # note: value can be None value = attrs.get(attr) if tag == 'link' and (rel := attrs.get('rel', '').lower()) \ and ('dns-prefetch' in rel or 'preconnect' in rel): if ':' in value: value = value.split(':', 1)[1] value = 'dns:' + value.rstrip('/') # parse tag for URLs self.parse_tag(tag, attr, value, name, base, lineno, column) log.debug(LOG_CHECK, "LinkFinder finished tag %s", tag) def get_link_name(self, tag, attrs, attr, name=None): """Parse attrs for link name. Return name of link.""" if tag == 'a' and attr == 'href': if not name: name = attrs.get('title', '') elif tag == 'img': name = attrs.get('alt', '') if not name: name = attrs.get('title', '') else: name = "" return name def parse_tag(self, tag, attr, value, name, base, lineno, column): """Add given url data to url list.""" assert isinstance(tag, str), repr(tag) assert isinstance(attr, str), repr(attr) assert isinstance(name, str), repr(name) assert isinstance(base, str), repr(base) assert isinstance(value, str) or value is None, repr(value) # look for meta refresh if tag == 'meta' and value: mo = refresh_re.match(value) if mo: self.found_url(mo.group("url"), name, base, lineno, column) elif attr != 'content': self.found_url(value, name, base, lineno, column) elif attr == 'style' and value: for mo in css_url_re.finditer(value): url = unquote(mo.group("url"), matching=True) self.found_url(url, name, base, lineno, column) elif attr == 'archive': for url in value.split(','): self.found_url(url, name, base, lineno, column) elif attr == 'srcset': for url in parse_srcset(value): self.found_url(url, name, base, lineno, column) else: self.found_url(value, name, base, lineno, column) def found_url(self, url, name, base, lineno, column): """Add newly found URL to queue.""" assert isinstance(url, str) or url is None, repr(url) self.callback(url, line=lineno, column=column, name=name, base=base) def find_links(soup, callback, tags): """Parse into content and search for URLs to check. When a URL is found it is passed to the supplied callback. """ lf = LinkFinder(callback, tags) for element in soup.find_all(True): lf.html_element( element.name, element.attrs, element.text.strip(), element.sourceline, None if element.sourcepos is None else element.sourcepos + 1, ) linkchecker-10.5.0/linkcheck/htmlutil/loginformsearch.py000066400000000000000000000040341466565367000234330ustar00rootroot00000000000000# Copyright (C) 2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ HTML form utils """ from ..htmlutil import htmlsoup from .. import log, LOG_CHECK class Form: """Store HTML form URL and form data.""" def __init__(self, url): """Set URL and empty form data.""" self.url = url self.data = {} def add_value(self, key, value): """Add a form value.""" self.data[key] = value def __repr__(self): """Return string displaying URL and form data.""" return f"" def search_form(content, cgiuser, cgipassword): """Search for a HTML form in the given HTML content that has input elements with name attributes that match cgiuser and/or cgipassword. If no such form is found return None. """ soup = htmlsoup.make_soup(content) cginames = {cgiuser, cgipassword} - {None} for form_element in soup.find_all("form", action=True): form = Form(form_element["action"]) for input_element in form_element.find_all("input", attrs={"name": True}): form.add_value(input_element["name"], input_element.attrs.get("value")) if cginames <= set(form.data): log.debug(LOG_CHECK, "Found form %s", form) return form # not found log.warn(LOG_CHECK, "Form with fields %s not found", ",".join(cginames)) return None linkchecker-10.5.0/linkcheck/htmlutil/srcsetparse.py000066400000000000000000000057731466565367000226220ustar00rootroot00000000000000# Copyright (C) 2022 Stefan Fisk # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ srcset attribute parser """ _TAB = '\u0009' _LF = '\u000A' _FF = '\u000C' _CR = '\u000D' _SPACE = '\u0020' _COMMA = '\u002C' _LEFT_PARENTHESIS = '\u0028' _RIGHT_PARENTHESIS = '\u0029' _WHITESPACE = {_TAB, _LF, _FF, _CR, _SPACE} _WHITESPACE_OR_COMMA = _WHITESPACE | {_COMMA} def parse_srcset(input): """ Parse HTML srcset Based on WhatWG HTML standard § 4.8.4.3.10 Parsing a srcset attribute, but does not parse or validate descriptors. https://html.spec.whatwg.org/multipage/images.html#parse-a-srcset-attribute """ input_end = len(input) position = 0 urls = [] while position < input_end: # 4. Splitting loop: Collect a sequence of code points that are ASCII # whitespace or U+002C COMMA characters from input given position. while position < input_end and input[position] in _WHITESPACE_OR_COMMA: position += 1 # 5. If position is past the end of input, return candidates. if position >= input_end: return urls # 6. Collect a sequence of code points that are not ASCII # whitespace from input given position, and let that be url. url_start = position while position < input_end and input[position] not in _WHITESPACE: position += 1 url_end = position # 8, If url ends with U+002C (,), then: if input[url_end - 1] == _COMMA: # Remove all trailing U+002C COMMA characters from url. while url_end > url_start and input[url_end - 1] == _COMMA: url_end -= 1 else: # This is a shortened version of 1–4 that simply skips the # descriptors while position < input_end: if input[position] == _LEFT_PARENTHESIS: # Skip until first closing parenthesis while (position < input_end and input[position] != _RIGHT_PARENTHESIS): position += 1 elif input[position] == _COMMA: break position += 1 # 9-15 is parsing and validation of the descriptors, which we ignore # If we found an URL if url_end > url_start: urls.append(input[url_start:url_end]) return urls linkchecker-10.5.0/linkcheck/httputil.py000066400000000000000000000036501466565367000202670ustar00rootroot00000000000000# Copyright (C) 2005-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. def x509_to_dict(x509): """Parse a x509 pyopenssl object to a dictionary with keys subject, subjectAltName and optional notAfter. """ from cryptography.x509 import DNSName, SubjectAlternativeName crypto_cert = x509.to_cryptography() ext = crypto_cert.extensions.get_extension_for_class(SubjectAlternativeName) res = { 'subject': ((('commonName', x509.get_subject().CN),),), 'subjectAltName': [ ('DNS', value) for value in ext.value.get_values_for_type(DNSName)] } try: # cryptography >= 42.0.0 notAfter = crypto_cert.not_valid_after_utc except AttributeError: notAfter = crypto_cert.not_valid_after if notAfter is not None: res['notAfter'] = notAfter.strftime('%b %d %H:%M:%S %Y GMT') return res def get_content_type(headers): """ Get the MIME type from the Content-Type header value, or 'application/octet-stream' if not found. @return: MIME type @rtype: string """ ptype = headers.get('Content-Type', 'application/octet-stream') if ";" in ptype: # split off not needed extension info ptype = ptype.split(';')[0] return ptype.strip().lower() linkchecker-10.5.0/linkcheck/i18n.py000066400000000000000000000030701466565367000171650ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Application internationalization support. """ # i18n support import locale import gettext import sys import codecs default_encoding = None def init(domain, directory): """Initialize this gettext i18n module and install the gettext translator class.""" global default_encoding default_encoding = locale.getpreferredencoding(False) translator = gettext.translation(domain, localedir=directory, fallback=True) import builtins builtins.__dict__['_'] = translator.gettext builtins.__dict__['_n'] = translator.ngettext def get_encoded_writer(out=sys.stdout, encoding=None, errors='replace'): """Get wrapped output writer with given encoding and error handling.""" if encoding is None: encoding = default_encoding Writer = codecs.getwriter(encoding) return Writer(out.buffer, errors) linkchecker-10.5.0/linkcheck/lc_cgi.py000066400000000000000000000200321466565367000176230ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Functions used by the WSGI script. """ import html import threading import locale import re import time import urllib.parse from . import ( configuration, strformat, checker, director, get_link_pat, init_i18n, url as urlutil, ) from .decorators import synchronized # 5 minutes timeout for requests MAX_REQUEST_SECONDS = 300 # character set encoding for HTML output HTML_ENCODING = 'utf-8' def application(environ, start_response): """WSGI interface: start an URL check.""" # the environment variable CONTENT_LENGTH may be empty or missing try: request_body_size = int(environ.get('CONTENT_LENGTH', 0)) except ValueError: request_body_size = 0 # When the method is POST the query string will be sent # in the HTTP request body which is passed by the WSGI server # in the file like wsgi.input environment variable. if request_body_size > 0: request_body = environ['wsgi.input'].read(request_body_size) else: request_body = environ['wsgi.input'].read() form = urllib.parse.parse_qs(request_body.decode(HTML_ENCODING)) status = '200 OK' start_response(status, get_response_headers()) yield from checklink(form=form, env=environ) _supported_langs = ('de', 'C') # map language -> locale name lang_locale = { 'de': 'de_DE', 'C': 'C', 'en': 'en_EN', } _is_level = re.compile(r'^(0|1|2|3|-1)$').match class LCFormError(Exception): """Form related errors.""" pass def get_response_headers(): """Get list of response headers in key-value form.""" return [ ("Content-type", "text/html"), ("Cache-Control", "no-cache"), ("Pragma:", "no-cache"), ] def formvalue(form, key): """Get value with given key from WSGI form.""" field = form.get(key) if isinstance(field, list): field = field[0] return field _lock = threading.Lock() class ThreadsafeIO: """Thread-safe unicode I/O class.""" def __init__(self): """Initialize buffer.""" self.buf = [] self.closed = False @synchronized(_lock) def write(self, data): """Write given unicode data to buffer.""" assert isinstance(data, str) if self.closed: raise OSError("Write on closed I/O object") if data: self.buf.append(data) @synchronized(_lock) def get_data(self): """Get bufferd unicode data.""" data = "".join(self.buf) self.buf = [] return data @synchronized(_lock) def close(self): """Reset buffer and close this I/O object.""" self.buf = [] self.closed = True def encode(s): """Encode given string in HTML encoding.""" return s.encode(HTML_ENCODING, 'ignore') def checklink(form, env): """Validates the CGI form and checks the given links.""" if form is None: form = {} try: checkform(form, env) except LCFormError as err: log(env, err) yield encode(format_error(str(err))) return out = ThreadsafeIO() config = get_configuration(form, out) url = strformat.stripurl(formvalue(form, "url")) aggregate = director.get_aggregate(config) url_data = checker.get_url_from(url, 0, aggregate, extern=(0, 0)) aggregate.urlqueue.put(url_data) for html_str in start_check(aggregate, out): yield encode(html_str) out.close() def start_check(aggregate, out): """Start checking in background and write encoded output to out.""" # check in background t = threading.Thread(target=director.check_urls, args=(aggregate,)) t.start() # time to wait for new data sleep_seconds = 2 # current running time run_seconds = 0 while not aggregate.is_finished(): yield out.get_data() time.sleep(sleep_seconds) run_seconds += sleep_seconds if run_seconds > MAX_REQUEST_SECONDS: director.abort(aggregate) break yield out.get_data() def get_configuration(form, out): """Initialize a CGI configuration.""" config = configuration.Configuration() config["recursionlevel"] = int(formvalue(form, "level")) config["logger"] = config.logger_new('html', fd=out, encoding=HTML_ENCODING) config["status"] = False config["threads"] = 2 if "anchors" in form: config["enabledplugins"].append("AnchorCheck") if "errors" not in form: config["verbose"] = True # avoid checking of local files or other nasty stuff pat = "!^%s$" % urlutil.safe_url_pattern config["externlinks"].append(get_link_pat(pat, strict=True)) config.sanitize() return config def get_host_name(form): """Return host name of given URL.""" return urllib.parse.urlparse(formvalue(form, "url"))[1] def checkform(form, env): """Check form data. throw exception on error Be sure to NOT print out any user-given data as HTML code, so use only plain strings as exception text.""" # check lang support if "language" in form: lang = formvalue(form, 'language') if lang in _supported_langs: localestr = lang_locale[lang] try: # XXX this is not thread-safe, so think of something else locale.setlocale(locale.LC_ALL, localestr) init_i18n() except locale.Error as errmsg: log(env, _("could not set locale %r: %s") % (localestr, errmsg)) else: raise LCFormError(_("unsupported language %r") % lang) # check url syntax if "url" in form: url = formvalue(form, "url") if not url or url == "http://": raise LCFormError(_("empty url was given")) if not urlutil.is_safe_url(url): raise LCFormError(_("disallowed url %r was given") % url) else: raise LCFormError(_("no url was given")) # check recursion level if "level" in form: level = formvalue(form, "level") if not _is_level(level): raise LCFormError(_("invalid recursion level %r") % level) # check options for option in ("anchors", "errors", "intern"): if option in form: value = formvalue(form, option) if value != "on": raise LCFormError(_("invalid %s option %r") % (option, value)) def log(env, msg): """Log message to WSGI error output.""" logfile = env['wsgi.errors'] logfile.write("%s\n" % msg) def dump(env, form): """Log environment and form.""" for var, value in env.items(): log(env, var + "=" + value) for key in form: log(env, str(formvalue(form, key))) def format_error(why): """Format standard error page. @param why: error message @type why: unicode @return: HTML page content @rtype: unicode """ return ( _( """ LinkChecker Online Error
Error: %s
The LinkChecker Online script has encountered an error. Please ensure that your provided URL link begins with http:// and contains only these characters: A-Za-z0-9./_~-

Errors are logged.
""" ) % html.escape(why) ) linkchecker-10.5.0/linkcheck/loader.py000066400000000000000000000067321466565367000176640ustar00rootroot00000000000000# Copyright (C) 2012-2014 Bastian Kleineidam """ Functions to load plugin modules. Example usage:: modules = loader.get_package_modules('plugins') plugins = loader.get_plugins(modules, PluginClass) """ import os import importlib.util import pkgutil from .fileutil import is_writable_by_others def check_writable_by_others(filename): """Check if file is writable by others on POSIX systems. On non-POSIX systems the check is ignored.""" if os.name != 'posix': # XXX on non-posix systems other bits are relevant return return is_writable_by_others(filename) def get_package_modules(packagename, packagepath): """Find all valid modules in the given package which must be a folder in the same directory as this loader.py module. A valid module has a .py extension, and is importable. @return: all loaded valid modules @rtype: iterator of module """ for mod in pkgutil.iter_modules(packagepath): if not mod.ispkg: try: name = f"..{packagename}.{mod.name}" yield importlib.import_module(name, __name__) except ImportError as msg: print(_("WARN: could not load module %s: %s") % (mod.name, msg)) def get_folder_modules(folder, parentpackage): """.""" if check_writable_by_others(folder): print("ERROR: refuse to load modules from world writable folder %r" % folder) return for filename in get_importable_files(folder): fullname = os.path.join(folder, filename) modname = parentpackage + "." + filename[:-3] try: spec = importlib.util.spec_from_file_location(modname, fullname) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) yield module except ImportError as msg: print(_("WARN: could not load file %s: %s") % (fullname, msg)) def get_importable_files(folder): """Find all module files in the given folder that end with '.py' and don't start with an underscore. @return: module names @rtype: iterator of string """ for fname in os.listdir(folder): if fname.endswith('.py') and not fname.startswith('_'): fullname = os.path.join(folder, fname) if check_writable_by_others(fullname): print( "ERROR: refuse to load module from world writable file %r" % fullname ) else: yield fname def get_plugins(modules, classes): """Find all given (sub-)classes in all modules. @param modules: the modules to search @type modules: iterator of modules @return: found classes @rtype: iterator of class objects """ for module in modules: yield from get_module_plugins(module, classes) def get_module_plugins(module, classes): """Return all subclasses of a class in the module. If the module defines __all__, only those entries will be searched, otherwise all objects not starting with '_' will be searched. """ try: names = module.__all__ except AttributeError: names = [x for x in vars(module) if not x.startswith('_')] for name in names: try: obj = getattr(module, name) except AttributeError: continue try: for classobj in classes: if issubclass(obj, classobj): yield obj except TypeError: continue linkchecker-10.5.0/linkcheck/lock.py000066400000000000000000000047271466565367000173500ustar00rootroot00000000000000# Copyright (C) 2005-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Locking utility class. """ import threading from . import log, LOG_THREAD def get_lock(name, debug=False): """Get a new lock. @param debug: if True, acquire() and release() will have debug messages @type debug: boolean, default is False @return: a lock object @rtype: threading.Lock or DebugLock """ lock = threading.Lock() # for thread debugging, use the DebugLock wrapper if debug: lock = DebugLock(lock, name) return lock class DebugLock: """Debugging lock class.""" def __init__(self, lock, name): """Store lock and name parameters.""" self.lock = lock self.name = name def acquire(self, blocking=1): """Acquire lock.""" threadname = threading.current_thread().name log.debug(LOG_THREAD, "Acquire %s for %s", self.name, threadname) self.lock.acquire(blocking) log.debug(LOG_THREAD, "...acquired %s for %s", self.name, threadname) def release(self): """Release lock.""" threadname = threading.current_thread().name log.debug(LOG_THREAD, "Release %s for %s", self.name, threadname) self.lock.release() def get_semaphore(name, value=None, debug=False): """Get a new semaphore. @param value: if not None, a BoundedSemaphore will be used @type debug: int or None @param debug: if True, acquire() and release() will have debug messages @type debug: boolean, default is False @return: a semaphore object @rtype: threading.Semaphore or threading.BoundedSemaphore or DebugLock """ if value is None: lock = threading.Semaphore() else: lock = threading.BoundedSemaphore(value) if debug: lock = DebugLock(lock, name) return lock linkchecker-10.5.0/linkcheck/log.py000066400000000000000000000074541466565367000172010ustar00rootroot00000000000000# Copyright (C) 2003-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Logging and debug functions. """ from io import StringIO import logging import os import inspect import traceback # memory leak debugging # import gc # gc.enable() # gc.set_debug(gc.DEBUG_LEAK) PRINT_LOCALVARS = False def _stack_format(stack): """Format a stack trace to a message. @return: formatted stack message @rtype: string """ s = StringIO() s.write('Traceback:') s.write(os.linesep) for frame, fname, lineno, method, lines, dummy in reversed(stack): s.write(' File %r, line %d, in %s' % (fname, lineno, method)) s.write(os.linesep) s.write(' %s' % lines[0].lstrip()) if PRINT_LOCALVARS: for key, value in frame.f_locals.items(): s.write(" %s = " % key) # be careful not to cause a new error in the error output try: s.write(repr(value)) s.write(os.linesep) except Exception: s.write("error in repr() call%s" % os.linesep) return s.getvalue() def _log(fun, msg, args, **kwargs): """Log a message with given function. Optional the following keyword arguments are supported: traceback(bool) - if True print traceback of current function exception(bool) - if True print last exception traceback @return: None """ fun(msg, *args) if kwargs.get("traceback"): # note: get rid of last parts of the stack fun(_stack_format(inspect.stack()[2:])) if kwargs.get("exception"): fun(traceback.format_exc()) def debug(logname, msg, *args, **kwargs): """Log a debug message. return: None """ log = logging.getLogger(logname) if log.isEnabledFor(logging.DEBUG): _log(log.debug, msg, args, **kwargs) def info(logname, msg, *args, **kwargs): """Log an informational message. return: None """ log = logging.getLogger(logname) if log.isEnabledFor(logging.INFO): _log(log.info, msg, args, **kwargs) def warn(logname, msg, *args, **kwargs): """Log a warning. return: None """ log = logging.getLogger(logname) if log.isEnabledFor(logging.WARN): _log(log.warning, msg, args, **kwargs) def error(logname, msg, *args, **kwargs): """Log an error. return: None """ log = logging.getLogger(logname) if log.isEnabledFor(logging.ERROR): _log(log.error, msg, args, **kwargs) def critical(logname, msg, *args, **kwargs): """Log a critical error. return: None """ log = logging.getLogger(logname) if log.isEnabledFor(logging.CRITICAL): _log(log.critical, msg, args, **kwargs) def exception(logname, msg, *args, **kwargs): """Log an exception. return: None """ log = logging.getLogger(logname) if log.isEnabledFor(logging.ERROR): _log(log.exception, msg, args, **kwargs) def is_debug(logname): """See if logger is on debug level.""" return logging.getLogger(logname).isEnabledFor(logging.DEBUG) def shutdown(): """Flush and close all log handlers.""" logging.shutdown() linkchecker-10.5.0/linkcheck/logconf.py000066400000000000000000000057561466565367000200520ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Logging configuration """ import logging.config import sys from . import ansicolor # application log areas LOG_ROOT = "linkcheck" LOG_CMDLINE = "linkcheck.cmdline" LOG_CHECK = "linkcheck.check" LOG_CACHE = "linkcheck.cache" LOG_THREAD = "linkcheck.thread" LOG_PLUGIN = "linkcheck.plugin" lognames = { "cmdline": LOG_CMDLINE, "checking": LOG_CHECK, "cache": LOG_CACHE, "thread": LOG_THREAD, "plugin": LOG_PLUGIN, "all": LOG_ROOT, } lognamelist = ", ".join(repr(name) for name in lognames) # logging configuration configdict = { 'version': 1, 'loggers': {}, 'root': {'level': 'WARN'}, 'incremental': True, } def init_log_config(handler=None): """Set up the application logging (not to be confused with check loggers). """ for applog in lognames.values(): # propagate except for root app logger 'linkcheck' propagate = applog != LOG_ROOT configdict['loggers'][applog] = dict(level='INFO', propagate=propagate) logging.config.dictConfig(configdict) if handler is None: handler = ansicolor.ColoredStreamHandler(strm=sys.stderr) add_loghandler(handler) def add_loghandler(handler): """Add log handler to root logger and LOG_ROOT and set formatting.""" format = "%(levelname)s %(name)s %(asctime)s %(threadName)s %(message)s" handler.setFormatter(logging.Formatter(format)) logging.getLogger(LOG_ROOT).addHandler(handler) logging.getLogger().addHandler(handler) def remove_loghandler(handler): """Remove log handler from root logger and LOG_ROOT.""" logging.getLogger(LOG_ROOT).removeHandler(handler) logging.getLogger().removeHandler(handler) def reset_loglevel(): """Reset log level to display only warnings and errors.""" set_loglevel(['all'], logging.WARN) def set_debug(loggers): """Set debugging log level.""" set_loglevel(loggers, logging.DEBUG) # enable for httplib debugging (used by requests.packages.urllib3) # import httplib # httplib.HTTPConnection.debuglevel = 1 def set_loglevel(loggers, level): """Set logging levels for given loggers.""" if not loggers: return if 'all' in loggers: loggers = lognames.keys() for key in loggers: logging.getLogger(lognames[key]).setLevel(level) linkchecker-10.5.0/linkcheck/logger/000077500000000000000000000000001466565367000173135ustar00rootroot00000000000000linkchecker-10.5.0/linkcheck/logger/__init__.py000066400000000000000000000351001466565367000214230ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Output logging support for different formats. """ import sys import os import datetime import time import codecs import abc from .. import log, LOG_CHECK, strformat, dummy, configuration, i18n _ = lambda x: x # noqa: E731 Fields = dict( realurl=_("Real URL"), cachekey=_("Cache key"), result=_("Result"), base=_("Base"), name=_("Name"), parenturl=_("Parent URL"), extern=_("Extern"), info=_("Info"), warning=_("Warning"), dltime=_("D/L time"), dlsize=_("Size"), checktime=_("Check time"), url=_("URL"), level=_("Level"), modified=_("Modified"), ) del _ ContentTypes = dict(image=0, text=0, video=0, audio=0, application=0, mail=0, other=0) class LogStatistics: """Gather log statistics: - number of errors, warnings and valid links - type of contents (image, video, audio, text, ...) - URL lengths """ def __init__(self): """Initialize log statistics.""" self.reset() def reset(self): """Reset all log statistics to default values.""" # number of logged URLs self.number = 0 # number of encountered URL errors self.errors = 0 # number of URL errors that were printed self.errors_printed = 0 # number of URL warnings self.warnings = 0 # number of URL warnings that were printed self.warnings_printed = 0 # number of internal errors self.internal_errors = 0 # link types self.link_types = ContentTypes.copy() # URL length statistics self.max_url_length = 0 self.min_url_length = 0 self.avg_url_length = 0.0 self.avg_number = 0 # overall downloaded bytes self.downloaded_bytes = None def log_url(self, url_data, do_print): """Log URL statistics.""" self.number += 1 if not url_data.valid: self.errors += 1 if do_print: self.errors_printed += 1 num_warnings = len(url_data.warnings) self.warnings += num_warnings if do_print: self.warnings_printed += num_warnings if url_data.content_type: key = url_data.content_type.split('/', 1)[0].lower() if key not in self.link_types: key = "other" elif url_data.url.startswith("mailto:"): key = "mail" else: key = "other" self.link_types[key] += 1 if url_data.url: n = len(url_data.url) self.max_url_length = max(n, self.max_url_length) if self.min_url_length == 0: self.min_url_length = n else: self.min_url_length = min(n, self.min_url_length) # track average number separately since empty URLs do not count self.avg_number += 1 # calculate running average self.avg_url_length += (n - self.avg_url_length) / self.avg_number def log_internal_error(self): """Increase internal error count.""" self.internal_errors += 1 class _Logger(abc.ABC): """ Base class for logging of checked urls. It defines the public API (see below) and offers basic functionality for all loggers. Each logger offers the following functions: * start_output() Initialize and start log output. Most loggers print a comment with copyright information. * end_output(**kwargs) Finish log output, possibly flushing buffers. Most loggers also print some statistics. Custom keyword arguments can be given for different loggers. * log_filter_url(url_data, do_print) Log a checked URL. The url_data object is a transport form of the UrlData class. The do_print flag indicates if this URL should be logged or just used to update internal statistics. Each subclassed logger must implement the following functions: * start_output() Also call the base class implementation of this. * end_output(**kwargs) See above. * log_url(url_data) Log a checked URL. Called by log_filter_url if do_print is True. """ # A lowercase name for this logger, usable for option values LoggerName = None # Default log configuration LoggerArgs = {} def __init__(self, **args): """ Initialize a logger, looking for part restrictions in kwargs. """ if 'parts' in args and "all" not in args['parts']: # only log given parts self.logparts = args['parts'] else: # log all parts self.logparts = None # number of spaces before log parts for alignment self.logspaces = {} # maximum indent of spaces for alignment self.max_indent = 0 # log statistics self.stats = LogStatistics() # encoding of output encoding = args.get("encoding", i18n.default_encoding) try: encoding = codecs.lookup(encoding).name except LookupError: encoding = i18n.default_encoding self.output_encoding = encoding # how to handle codec errors self.codec_errors = "replace" # Flag to see if logger is active. Can be deactivated on errors. self.is_active = True def get_args(self, kwargs): """Construct log configuration from default and user args.""" args = dict(self.LoggerArgs) args.update(kwargs) return args def get_charset_encoding(self): """Translate the output encoding to a charset encoding name.""" if self.output_encoding == "utf-8-sig": return "utf-8" return self.output_encoding def encode(self, s): """Encode string with output encoding.""" assert isinstance(s, str) return s.encode(self.output_encoding, self.codec_errors) def init_fileoutput(self, args): """ Initialize self.fd file descriptor from args. For file output (used when the fileoutput arg is given), the self.fd initialization is deferred until the first self.write() call. This avoids creation of an empty file when no output is written. """ self.filename = None self.close_fd = False self.fd = None if args.get('fileoutput'): self.filename = os.path.expanduser(args['filename']) elif 'fd' in args: self.fd = args['fd'] else: self.fd = self.create_fd() def start_fileoutput(self): """Start output to configured file.""" path = os.path.dirname(self.filename) try: if path and not os.path.isdir(path): os.makedirs(path) self.fd = self.create_fd() self.close_fd = True except OSError: msg = sys.exc_info()[1] log.warn( LOG_CHECK, "Could not open file %r for writing: %s\n" "Disabling log output of %s", self.filename, msg, self, ) self.fd = dummy.Dummy() self.is_active = False self.filename = None def create_fd(self): """Create open file descriptor.""" if self.filename is None: return i18n.get_encoded_writer( encoding=self.output_encoding, errors=self.codec_errors ) return codecs.open(self.filename, "wb", self.output_encoding, self.codec_errors) def close_fileoutput(self): """ Flush and close the file output denoted by self.fd. """ if self.fd is not None: try: self.flush() except OSError: # ignore flush errors pass if self.close_fd: try: self.fd.close() except OSError: # ignore close errors pass self.fd = None def check_date(self): """ Check for special dates. """ now = datetime.date.today() if now.day == 7 and now.month == 1: msg = _("Happy birthday for LinkChecker, I'm %d years old today!") self.comment(msg % (now.year - 2000)) def comment(self, s, **args): """ Write a comment and a newline. This method just prints the given string. """ self.writeln(s=s, **args) def wrap(self, lines, width): """ Return wrapped version of given lines. """ sep = os.linesep + os.linesep text = sep.join(lines) kwargs = dict( subsequent_indent=" " * self.max_indent, initial_indent=" " * self.max_indent, break_long_words=False, break_on_hyphens=False, ) return strformat.wrap(text, width, **kwargs).lstrip() def write(self, s, **args): """Write string to output descriptor. Strips control characters from string before writing. """ if self.filename is not None: self.start_fileoutput() if self.fd is None: # Happens when aborting threads times out log.warn(LOG_CHECK, "writing to uninitialized or closed file") else: try: self.fd.write(s, **args) except OSError: msg = sys.exc_info()[1] log.warn( LOG_CHECK, "Could not write to output file: %s\n" "Disabling log output of %s", msg, self, ) self.close_fileoutput() self.fd = dummy.Dummy() self.is_active = False def writeln(self, s="", **args): """ Write string to output descriptor plus a newline. """ self.write(f"{s}{os.linesep}", **args) def has_part(self, name): """ See if given part name will be logged. """ if self.logparts is None: # log all parts return True return name in self.logparts def part(self, name): """ Return translated part name. """ return _(Fields.get(name, "")) def spaces(self, name): """ Return indent of spaces for given part name. """ return self.logspaces[name] def start_output(self): """ Start log output. """ # map with spaces between part name and value if self.logparts is None: parts = Fields.keys() else: parts = self.logparts values = (self.part(x) for x in parts) # maximum indent for localized log part names self.max_indent = max(len(x) for x in values) + 1 for key in parts: numspaces = self.max_indent - len(self.part(key)) self.logspaces[key] = " " * numspaces self.stats.reset() self.starttime = time.time() def log_filter_url(self, url_data, do_print): """ Log a new url with this logger if do_print is True. Else only update accounting data. """ self.stats.log_url(url_data, do_print) if do_print: self.log_url(url_data) def write_intro(self): """Write intro comments.""" self.comment( _("created by %(app)s at %(time)s") % {"app": configuration.AppName, "time": strformat.strtime(self.starttime)} ) self.comment( _("Read the documentation at %(url)s") % {'url': configuration.Url} ) self.comment( _("Write comments and bugs to %(url)s") % {'url': configuration.SupportUrl} ) self.check_date() def write_outro(self): """Write outro comments.""" self.stoptime = time.time() duration = self.stoptime - self.starttime self.comment( _("Stopped checking at %(time)s (%(duration)s)") % { "time": strformat.strtime(self.stoptime), "duration": strformat.strduration_long(duration), } ) @abc.abstractmethod def log_url(self, url_data): """ Log a new url with this logger. """ pass @abc.abstractmethod def end_output(self, **kwargs): """ End of output, used for cleanup (eg output buffer flushing). """ pass def __str__(self): """ Return class name. """ return self.__class__.__name__ def __repr__(self): """ Return class name. """ return repr(self.__class__.__name__) def flush(self): """ If the logger has internal buffers, flush them. Ignore flush I/O errors since we are not responsible for proper flushing of log output streams. """ if hasattr(self, "fd"): try: self.fd.flush() except (OSError, AttributeError): pass def log_internal_error(self): """Indicate that an internal error occurred in the program.""" log.warn(LOG_CHECK, "internal error occurred") self.stats.log_internal_error() def format_modified(self, modified, sep=" "): """Format modification date in UTC if it's not None. @param modified: modification date in UTC @type modified: datetime or None @return: formatted date or empty string @rtype: unicode """ if modified is not None: return modified.strftime(f"%Y-%m-%d{sep}%H:%M:%S.%fZ") return "" def _get_loggers(): """Return list of Logger classes.""" from .. import loader modules = loader.get_package_modules('logger', __path__) return list(loader.get_plugins(modules, [_Logger])) LoggerClasses = _get_loggers() LoggerNames = [x.LoggerName for x in LoggerClasses] LoggerKeys = ", ".join(repr(x) for x in LoggerNames) linkchecker-10.5.0/linkcheck/logger/csvlog.py000066400000000000000000000113521466565367000211640ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ A CSV logger. """ import csv from io import StringIO import os from . import _Logger Columns = ( "urlname", "parentname", "base", "result", "warningstring", "infostring", "valid", "url", "line", "column", "name", "dltime", "size", "checktime", "cached", "level", "modified", ) class CSVLogger(_Logger): """ CSV output, consisting of one line per entry. Entries are separated by a separator (a semicolon per default). """ LoggerName = "csv" LoggerArgs = { "filename": "linkchecker-out.csv", 'separator': ';', "quotechar": '"', "dialect": "excel", } def __init__(self, **kwargs): """Store default separator and (os dependent) line terminator.""" args = self.get_args(kwargs) super().__init__(**args) self.init_fileoutput(args) self.separator = args['separator'] self.quotechar = args['quotechar'] self.dialect = args['dialect'] self.linesep = os.linesep def comment(self, s, **args): """Write CSV comment.""" self.writeln(s="# %s" % s, **args) def start_output(self): """Write checking start info as csv comment.""" super().start_output() row = [] if self.has_part("intro"): self.write_intro() self.flush() else: # write empty string to initialize file output self.write("") self.queue = StringIO() self.writer = csv.writer( self.queue, dialect=self.dialect, delimiter=self.separator, lineterminator=self.linesep, quotechar=self.quotechar, ) for s in Columns: if self.has_part(s): row.append(s) if row: self.writerow(row) def log_url(self, url_data): """Write csv formatted url check info.""" row = [] if self.has_part("urlname"): row.append(url_data.base_url) if self.has_part("parentname"): row.append(url_data.parent_url) if self.has_part("base"): row.append(url_data.base_ref) if self.has_part("result"): row.append(url_data.result) if self.has_part("warningstring"): row.append(self.linesep.join(x[1] for x in url_data.warnings)) if self.has_part("infostring"): row.append(self.linesep.join(url_data.info)) if self.has_part("valid"): row.append(url_data.valid) if self.has_part("url"): row.append(url_data.url) if self.has_part("line") and url_data.line is not None: row.append(url_data.line) if self.has_part("column") and url_data.column is not None: row.append(url_data.column) if self.has_part("name"): row.append(url_data.name) if self.has_part("dltime"): row.append(url_data.dltime) if self.has_part("dlsize"): row.append(url_data.size) if self.has_part("checktime"): row.append(url_data.checktime) if self.has_part("cached"): row.append(0) if self.has_part("level"): row.append(url_data.level) if self.has_part("modified"): row.append(self.format_modified(url_data.modified)) self.writerow(row) self.flush() def writerow(self, row): """Write one row in CSV format.""" self.writer.writerow(row) # Fetch UTF-8 output from the queue ... data = self.queue.getvalue() try: data = data.decode("utf-8") except AttributeError: pass # ... and write to the target stream self.write(data) # empty queue self.queue.seek(0) self.queue.truncate(0) def end_output(self, **kwargs): """Write end of checking info as csv comment.""" if self.has_part("outro"): self.write_outro() self.close_fileoutput() linkchecker-10.5.0/linkcheck/logger/customxml.py000066400000000000000000000073461466565367000217320ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ An XML logger. """ from . import xmllog from .. import strformat class CustomXMLLogger(xmllog._XMLLogger): """ XML custom output for easy post-processing. """ LoggerName = "xml" LoggerArgs = { "filename": "linkchecker-out.xml", } def start_output(self): """ Write start of checking info as xml comment. """ super().start_output() self.xml_start_output() attrs = {"created": strformat.strtime(self.starttime)} self.xml_starttag('linkchecker', attrs) self.flush() def log_url(self, url_data): """ Log URL data in custom XML format. """ self.xml_starttag('urldata') if self.has_part('url'): self.xml_tag("url", url_data.base_url) if url_data.name and self.has_part('name'): self.xml_tag("name", url_data.name) if url_data.parent_url and self.has_part('parenturl'): attrs = { 'line': "%s" % url_data.line, 'column': "%s" % url_data.column, } self.xml_tag("parent", url_data.parent_url, attrs=attrs) if url_data.base_ref and self.has_part('base'): self.xml_tag("baseref", url_data.base_ref) if self.has_part("realurl"): self.xml_tag("realurl", url_data.url) if self.has_part("extern"): self.xml_tag("extern", "%d" % (1 if url_data.extern else 0)) if url_data.dltime >= 0 and self.has_part("dltime"): self.xml_tag("dltime", "%f" % url_data.dltime) if url_data.size >= 0 and self.has_part("dlsize"): self.xml_tag("dlsize", "%d" % url_data.size) if url_data.checktime and self.has_part("checktime"): self.xml_tag("checktime", "%f" % url_data.checktime) if self.has_part("level"): self.xml_tag("level", "%d" % url_data.level) if url_data.info and self.has_part('info'): self.xml_starttag("infos") for info in url_data.info: self.xml_tag("info", info) self.xml_endtag("infos") if url_data.modified and self.has_part('modified'): self.xml_tag("modified", self.format_modified(url_data.modified)) if url_data.warnings and self.has_part('warning'): self.xml_starttag("warnings") for tag, data in url_data.warnings: attrs = {} if tag: attrs["tag"] = tag self.xml_tag("warning", data, attrs) self.xml_endtag("warnings") if self.has_part("result"): attrs = {} if url_data.result: attrs["result"] = url_data.result self.xml_tag("valid", "%d" % (1 if url_data.valid else 0), attrs) self.xml_endtag('urldata') self.flush() def end_output(self, **kwargs): """ Write XML end tag. """ self.xml_endtag("linkchecker") self.xml_end_output() self.close_fileoutput() linkchecker-10.5.0/linkcheck/logger/dot.py000066400000000000000000000060751466565367000204630ustar00rootroot00000000000000# Copyright (C) 2005-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ A DOT graph format logger. The specification has been taken from https://www.graphviz.org/doc/info/lang.html """ from .graph import _GraphLogger class DOTLogger(_GraphLogger): """ Generates .dot sitemap graphs. Use graphviz to see the sitemap graph. """ LoggerName = "dot" LoggerArgs = { "filename": "linkchecker-out.dot", "encoding": "ascii", } def start_output(self): """Write start of checking info as DOT comment.""" super().start_output() if self.has_part("intro"): self.write_intro() self.writeln() self.writeln("digraph G {") self.writeln(" graph [") self.writeln(" charset=\"%s\"," % self.get_charset_encoding()) self.writeln(" ];") self.flush() def comment(self, s, **args): """Write DOT comment.""" self.write("// ") self.writeln(s=s, **args) def log_url(self, url_data): """Write one node.""" node = self.get_node(url_data) if node is not None: self.writeln(' "%s" [' % dotquote(node["label"])) if self.has_part("realurl"): self.writeln(' href="%s",' % dotquote(node["url"])) if node["dltime"] >= 0 and self.has_part("dltime"): self.writeln(" dltime=%d," % node["dltime"]) if node["size"] >= 0 and self.has_part("dlsize"): self.writeln(" size=%d," % node["size"]) if node["checktime"] and self.has_part("checktime"): self.writeln(" checktime=%d," % node["checktime"]) if self.has_part("extern"): self.writeln(" extern=%d," % node["extern"]) self.writeln(" ];") def write_edge(self, node): """Write edge from parent to node.""" source = dotquote(self.nodes[node["parent_url"]]["label"]) target = dotquote(node["label"]) self.writeln(f' "{source}" -> "{target}" [') self.writeln(f' label="{dotquote(node["edge"])}",') if self.has_part("result"): self.writeln(f' valid={node["valid"]},') self.writeln(" ];") def end_graph(self): """Write end of graph marker.""" self.writeln("}") def dotquote(s): """Quote string for usage in DOT output format.""" return s.replace('"', '\\"') linkchecker-10.5.0/linkcheck/logger/failures.py000066400000000000000000000072471466565367000215110ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ A failures logger. """ import os from . import _Logger from .. import log, LOG_CHECK from ..configuration import get_user_data class FailuresLogger(_Logger): """ Updates a list of failed links. If a link already on the list is found to be working, it is removed. After n days we only have links on the list which failed within those n days. """ LoggerName = "failures" LoggerArgs = { "filename": os.path.join(get_user_data(), "failures"), } def __init__(self, **kwargs): """Initialize with old failures data (if found).""" blacklist = os.path.join(get_user_data(), "blacklist") if os.path.isfile(blacklist): self.LoggerArgs["filename"] = blacklist log.warn( LOG_CHECK, _("%(blacklist)s file is deprecated please rename to failures") % {"blacklist": blacklist} ) args = self.get_args(kwargs) super().__init__(**args) self.init_fileoutput(args) self.failures = {} if self.filename is not None and os.path.exists(self.filename): self.read_failures() def comment(self, s, **args): """ Write nothing. """ pass def log_url(self, url_data): """ Add invalid url to failures, delete valid url from failures. """ key = (url_data.parent_url, url_data.cache_url) key = repr(key) if key in self.failures: if url_data.valid: del self.failures[key] else: self.failures[key] += 1 else: if not url_data.valid: self.failures[key] = 1 def end_output(self, **kwargs): """ Write failures file. """ self.write_failures() def read_failures(self): """ Read a previously stored failures from file fd. """ with open(self.filename, encoding=self.output_encoding, errors=self.codec_errors) as fd: for line in fd: line = line.rstrip() if line.startswith('#') or not line: continue value, key = line.split(None, 1) key = key.strip('"') if not key.startswith('('): log.critical( LOG_CHECK, _("invalid line starting with '%(linestart)s' in %(failures)s") % {"linestart": line[:12], "failures": self.filename} ) raise SystemExit(2) self.failures[key] = int(value) def write_failures(self): """ Write the failures file. """ oldmask = os.umask(0o077) for key, value in self.failures.items(): self.write("%d %s%s" % (value, repr(key), os.linesep)) self.close_fileoutput() # restore umask os.umask(oldmask) linkchecker-10.5.0/linkcheck/logger/gml.py000066400000000000000000000054121466565367000204460ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ A gml logger. """ from .graph import _GraphLogger class GMLLogger(_GraphLogger): """GML means Graph Modeling Language. Use a GML tool to see the sitemap graph.""" LoggerName = 'gml' LoggerArgs = { "filename": "linkchecker-out.gml", } def start_output(self): """Write start of checking info as gml comment.""" super().start_output() if self.has_part("intro"): self.write_intro() self.writeln() self.writeln("graph [") self.writeln(" directed 1") self.flush() def comment(self, s, **args): """Write GML comment.""" self.writeln(s='comment "%s"' % s, **args) def log_url(self, url_data): """Write one node.""" node = self.get_node(url_data) if node: self.writeln(" node [") self.writeln(" id %d" % node["id"]) self.writeln(' label "%s"' % node["label"]) if self.has_part("realurl"): self.writeln(' url "%s"' % node["url"]) if node["dltime"] >= 0 and self.has_part("dltime"): self.writeln(" dltime %d" % node["dltime"]) if node["size"] >= 0 and self.has_part("dlsize"): self.writeln(" size %d" % node["size"]) if node["checktime"] and self.has_part("checktime"): self.writeln(" checktime %d" % node["checktime"]) if self.has_part("extern"): self.writeln(" extern %d" % node["extern"]) self.writeln(" ]") def write_edge(self, node): """Write one edge.""" self.writeln(" edge [") self.writeln(' label "%s"' % node["edge"]) self.writeln(" source %d" % self.nodes[node["parent_url"]]["id"]) self.writeln(" target %d" % node["id"]) if self.has_part("result"): self.writeln(" valid %d" % node["valid"]) self.writeln(" ]") def end_graph(self): """Write end of graph marker.""" self.writeln("]") linkchecker-10.5.0/linkcheck/logger/graph.py000066400000000000000000000064001466565367000207660ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Base class for graph loggers. """ from . import _Logger from ..decorators import notimplemented import re class _GraphLogger(_Logger): """Provide base method to get node data.""" def __init__(self, **kwargs): """Initialize graph node list and internal id counter.""" args = self.get_args(kwargs) super().__init__(**args) self.init_fileoutput(args) self.nodes = {} self.nodeid = 0 def log_filter_url(self, url_data, do_print): """Update accounting data and log all valid URLs regardless the do_print flag. """ self.stats.log_url(url_data, do_print) # ignore the do_print flag and determine ourselves if we filter the url if url_data.valid: self.log_url(url_data) def get_node(self, url_data): """Return new node data or None if node already exists.""" if not url_data.url: return None elif url_data.url in self.nodes: return None node = { "url": url_data.url, "parent_url": url_data.parent_url, "id": self.nodeid, "label": quote(url_data.title if url_data.title else url_data.name), "extern": 1 if url_data.extern else 0, "checktime": url_data.checktime, "size": url_data.size, "dltime": url_data.dltime, "edge": quote(url_data.name), "valid": 1 if url_data.valid else 0, } self.nodes[node["url"]] = node self.nodeid += 1 return node def write_edges(self): """ Write all edges we can find in the graph in a brute-force manner. """ for node in self.nodes.values(): if node["parent_url"] in self.nodes: self.write_edge(node) self.flush() @notimplemented def write_edge(self, node): """Write edge data for one node and its parent.""" pass @notimplemented def end_graph(self): """Write end-of-graph marker.""" pass def end_output(self, **kwargs): """Write edges and end of checking info as gml comment.""" self.write_edges() self.end_graph() if self.has_part("outro"): self.write_outro() self.close_fileoutput() _disallowed = re.compile(r"[^a-zA-Z0-9 '#(){}\-\[\]\.,;:\!\?]+") def quote(s): """Replace disallowed characters in node or edge labels. Also remove whitespace from beginning or end of label.""" return _disallowed.sub(" ", s).strip() linkchecker-10.5.0/linkcheck/logger/gxml.py000066400000000000000000000062651466565367000206450ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ A GraphXML logger. """ from .xmllog import _XMLLogger from .graph import _GraphLogger class GraphXMLLogger(_XMLLogger, _GraphLogger): """XML output mirroring the GML structure. Easy to parse with any XML tool.""" LoggerName = 'gxml' LoggerArgs = { "filename": "linkchecker-out.gxml", } def __init__(self, **kwargs): """Initialize graph node list and internal id counter.""" args = self.get_args(kwargs) super().__init__(**args) self.nodes = {} self.nodeid = 0 def start_output(self): """Write start of checking info as xml comment.""" super().start_output() self.xml_start_output() self.xml_starttag('GraphXML') self.xml_starttag('graph', attrs={"isDirected": "true"}) self.flush() def log_url(self, url_data): """Write one node and all possible edges.""" node = self.get_node(url_data) if node: self.xml_starttag('node', attrs={"name": "%d" % node["id"]}) self.xml_tag("label", node["label"]) if self.has_part("realurl"): self.xml_tag("url", node["url"]) self.xml_starttag("data") if node["dltime"] >= 0 and self.has_part("dltime"): self.xml_tag("dltime", "%f" % node["dltime"]) if node["size"] >= 0 and self.has_part("dlsize"): self.xml_tag("size", "%d" % node["size"]) if node["checktime"] and self.has_part("checktime"): self.xml_tag("checktime", "%f" % node["checktime"]) if self.has_part("extern"): self.xml_tag("extern", "%d" % node["extern"]) self.xml_endtag("data") self.xml_endtag("node") def write_edge(self, node): """Write one edge.""" attrs = { "source": "%d" % self.nodes[node["parent_url"]]["id"], "target": "%d" % node["id"], } self.xml_starttag("edge", attrs=attrs) self.xml_tag("label", node["label"]) self.xml_starttag("data") if self.has_part("result"): self.xml_tag("valid", "%d" % node["valid"]) self.xml_endtag("data") self.xml_endtag("edge") def end_output(self, **kwargs): """Finish graph output, and print end of checking info as xml comment.""" self.xml_endtag("graph") self.xml_endtag("GraphXML") self.xml_end_output() self.close_fileoutput() linkchecker-10.5.0/linkcheck/logger/html.py000066400000000000000000000340511466565367000206340ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ A HTML logger. """ import html import os import time from . import _Logger from .. import strformat, configuration # ss=1 enables show source validate_html = "https://validator.w3.org/check?ss=1&uri=%(uri)s" # options are the default validate_css = ( "https://jigsaw.w3.org/css-validator/validator?" "uri=%(uri)s&warning=1&profile=css2&usermedium=all" ) HTML_HEADER = """ %(title)s """ class HtmlLogger(_Logger): """Logger with HTML output.""" LoggerName = 'html' LoggerArgs = { "filename": "linkchecker-out.html", 'colorbackground': '#fff7e5', 'colorurl': '#dcd5cf', 'colorborder': '#000000', 'colorlink': '#191c83', 'colorwarning': '#e0954e', 'colorerror': '#db4930', 'colorok': '#3ba557', } def __init__(self, **kwargs): """Initialize default HTML color values.""" args = self.get_args(kwargs) super().__init__(**args) self.init_fileoutput(args) self.colorbackground = args['colorbackground'] self.colorurl = args['colorurl'] self.colorborder = args['colorborder'] self.colorlink = args['colorlink'] self.colorwarning = args['colorwarning'] self.colorerror = args['colorerror'] self.colorok = args['colorok'] def part(self, name): """Return non-space-breakable part name.""" return super().part(name).replace(" ", " ") def comment(self, s, **args): """Write HTML comment.""" self.write("") def start_output(self): """Write start of checking info.""" super().start_output() header = { "encoding": self.get_charset_encoding(), "title": configuration.App, "body": self.colorbackground, "link": self.colorlink, "vlink": self.colorlink, "alink": self.colorlink, "url": self.colorurl, "error": self.colorerror, "valid": self.colorok, "warning": self.colorwarning, } self.write(HTML_HEADER % header) self.comment("Generated by %s" % configuration.App) if self.has_part('intro'): self.write( "

" + configuration.App + "


" + configuration.Freeware + "

" + (_("Start checking at %s") % strformat.strtime(self.starttime)) + os.linesep + "
" ) self.check_date() self.flush() def log_url(self, url_data): """Write url checking info as HTML.""" self.write_table_start() if self.has_part("url"): self.write_url(url_data) if url_data.name and self.has_part("name"): self.write_name(url_data) if url_data.parent_url and self.has_part("parenturl"): self.write_parent(url_data) if url_data.base_ref and self.has_part("base"): self.write_base(url_data) if url_data.url and self.has_part("realurl"): self.write_real(url_data) if url_data.dltime >= 0 and self.has_part("dltime"): self.write_dltime(url_data) if url_data.size >= 0 and self.has_part("dlsize"): self.write_size(url_data) if url_data.checktime and self.has_part("checktime"): self.write_checktime(url_data) if url_data.info and self.has_part("info"): self.write_info(url_data) if url_data.modified and self.has_part("modified"): self.write_modified(url_data) if url_data.warnings and self.has_part("warning"): self.write_warning(url_data) if self.has_part("result"): self.write_result(url_data) self.write_table_end() self.flush() def write_table_start(self): """Start html table.""" self.writeln('

') def write_table_end(self): """End html table.""" self.write('

') def write_id(self): """Write ID for current URL.""" self.writeln("") self.writeln('%s' % self.part("id")) self.write("%d" % self.stats.number) def write_url(self, url_data): """Write url_data.base_url.""" self.writeln("") self.writeln('%s' % self.part("url")) self.write('') self.write("`%s'" % html.escape(url_data.base_url)) self.writeln("") def write_name(self, url_data): """Write url_data.name.""" args = (self.part("name"), html.escape(url_data.name)) self.writeln("%s`%s'" % args) def write_parent(self, url_data): """Write url_data.parent_url.""" self.write( "" + self.part("parenturl") + '' + html.escape(url_data.parent_url) + "" ) if url_data.line is not None: self.write(_(", line %d") % url_data.line) if url_data.column is not None: self.write(_(", col %d") % url_data.column) if url_data.page > 0: self.write(_(", page %d") % url_data.page) if not url_data.valid: # on errors show HTML and CSS validation for parent url vhtml = validate_html % {'uri': url_data.parent_url} vcss = validate_css % {'uri': url_data.parent_url} self.writeln() self.writeln('(HTML)') self.write('(CSS)') self.writeln("") def write_base(self, url_data): """Write url_data.base_ref.""" self.writeln( "" + self.part("base") + "" + html.escape(url_data.base_ref) + "" ) def write_real(self, url_data): """Write url_data.url.""" self.writeln( "" + self.part("realurl") + "" + '' + html.escape(url_data.url) + "" ) def write_dltime(self, url_data): """Write url_data.dltime.""" self.writeln( "" + self.part("dltime") + "" + (_("%.3f seconds") % url_data.dltime) + "" ) def write_size(self, url_data): """Write url_data.size.""" self.writeln( "" + self.part("dlsize") + "" + strformat.strsize(url_data.size) + "" ) def write_checktime(self, url_data): """Write url_data.checktime.""" self.writeln( "" + self.part("checktime") + "" + (_("%.3f seconds") % url_data.checktime) + "" ) def write_info(self, url_data): """Write url_data.info.""" sep = "
" + os.linesep text = sep.join(html.escape(x) for x in url_data.info) self.writeln( '' + self.part("info") + "" + text + "" ) def write_modified(self, url_data): """Write url_data.modified.""" text = html.escape(self.format_modified(url_data.modified)) self.writeln( '' + self.part("modified") + "" + text + "" ) def write_warning(self, url_data): """Write url_data.warnings.""" sep = "
" + os.linesep text = sep.join(html.escape(x[1]) for x in url_data.warnings) self.writeln( '' + self.part("warning") + '' + text + "" ) def write_result(self, url_data): """Write url_data.result.""" if url_data.valid: self.write('') self.write(self.part("result")) self.write('') self.write(html.escape(_("Valid"))) else: self.write('') self.write(self.part("result")) self.write('') self.write(html.escape(_("Error"))) if url_data.result: self.write(": " + html.escape(url_data.result)) self.writeln("") def write_stats(self): """Write check statistic infos.""" self.writeln('
%s
' % _("Statistics")) if self.stats.number > 0: self.writeln( _( "Content types: %(image)d image, %(text)d text, %(video)d video, " "%(audio)d audio, %(application)d application, %(mail)d mail" " and %(other)d other." ) % self.stats.link_types ) self.writeln("
") self.writeln( _("URL lengths: min=%(min)d, max=%(max)d, avg=%(avg)d.") % dict( min=self.stats.min_url_length, max=self.stats.max_url_length, avg=self.stats.avg_url_length, ) ) else: self.writeln(_("No statistics available since no URLs were checked.")) self.writeln("
") def write_outro(self): """Write end of check message.""" self.writeln("
") self.write(_("That's it.") + " ") if self.stats.number >= 0: self.write( _n("%d link checked.", "%d links checked.", self.stats.number) % self.stats.number ) self.write(" ") self.write( _n("%d warning found", "%d warnings found", self.stats.warnings_printed) % self.stats.warnings_printed ) if self.stats.warnings != self.stats.warnings_printed: self.write( _(" (%d ignored or duplicates not printed)") % (self.stats.warnings - self.stats.warnings_printed) ) self.write(". ") self.write( _n("%d error found", "%d errors found", self.stats.errors_printed) % self.stats.errors_printed ) if self.stats.errors != self.stats.errors_printed: self.write( _(" (%d duplicates not printed)") % (self.stats.errors - self.stats.errors_printed) ) self.writeln(".") self.writeln("
") num = self.stats.internal_errors if num: self.write( _n( "There was %(num)d internal error.", "There were %(num)d internal errors.", num, ) % {"num": num} ) self.writeln("
") self.stoptime = time.time() duration = self.stoptime - self.starttime self.writeln( _("Stopped checking at %(time)s (%(duration)s)") % { "time": strformat.strtime(self.stoptime), "duration": strformat.strduration_long(duration), } ) self.writeln( '


' + configuration.HtmlAppInfo + "
" ) self.writeln( _("Read the documentation at %s") % ( '' + configuration.Url + ".
" ) ) self.writeln( _("Write comments and bugs to %s") % ( '' + configuration.SupportUrl + ".
" ) ) self.writeln("
") def end_output(self, **kwargs): """Write end of checking info as HTML.""" if self.has_part("stats"): self.write_stats() if self.has_part("outro"): self.write_outro() self.close_fileoutput() linkchecker-10.5.0/linkcheck/logger/none.py000066400000000000000000000023371466565367000206310ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ A dummy logger. """ from . import _Logger class NoneLogger(_Logger): """ Dummy logger printing nothing. """ LoggerName = 'none' def comment(self, s, **args): """ Do nothing. """ pass def start_output(self): """ Do nothing. """ pass def log_url(self, url_data): """Do nothing.""" pass def end_output(self, **kwargs): """ Do nothing. """ pass linkchecker-10.5.0/linkcheck/logger/sitemapxml.py000066400000000000000000000103641466565367000220540ustar00rootroot00000000000000# Copyright (C) 2012-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ A sitemap XML logger. """ from . import xmllog from .. import log, LOG_CHECK ChangeFreqs = ( 'always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never', ) HTTP_SCHEMES = ('http:', 'https:') HTML_TYPES = ('text/html', "application/xhtml+xml") class SitemapXmlLogger(xmllog._XMLLogger): """Sitemap XML output according to https://www.sitemaps.org/protocol.html """ LoggerName = 'sitemap' LoggerArgs = { "filename": "linkchecker-out.sitemap.xml", "encoding": "utf-8", } def __init__(self, **kwargs): """Initialize graph node list and internal id counter.""" args = self.get_args(kwargs) super().__init__(**args) # All URLs must have the given prefix, which is determined # by the first logged URL. self.prefix = None # If first URL does not have a valid HTTP scheme, disable this # logger self.disabled = False if 'frequency' in args: if args['frequency'] not in ChangeFreqs: raise ValueError("Invalid change frequency %r" % args['frequency']) self.frequency = args['frequency'] else: self.frequency = 'daily' self.priority = None if 'priority' in args: self.priority = float(args['priority']) def start_output(self): """Write start of checking info as xml comment.""" super().start_output() self.xml_start_output() attrs = {"xmlns": "http://www.sitemaps.org/schemas/sitemap/0.9"} self.xml_starttag('urlset', attrs) self.flush() def log_filter_url(self, url_data, do_print): """Update accounting data and determine if URL should be included in the sitemap. """ self.stats.log_url(url_data, do_print) if self.disabled: return # initialize prefix and priority if self.prefix is None: if not url_data.url.startswith(HTTP_SCHEMES): log.warn( LOG_CHECK, "Sitemap URL %r does not start with http: or https:.", url_data.url, ) self.disabled = True return self.prefix = url_data.url # first URL (ie. the homepage) gets priority 1.0 per default priority = 1.0 elif url_data.url == self.prefix: return else: # all other pages get priority 0.5 per default priority = 0.5 if self.priority is not None: priority = self.priority # ignore the do_print flag and determine ourselves if we filter the url if ( url_data.valid and url_data.url.startswith(HTTP_SCHEMES) and url_data.url.startswith(self.prefix) and url_data.content_type in HTML_TYPES ): self.log_url(url_data, priority=priority) def log_url(self, url_data, priority=None): """Log URL data in sitemap format.""" self.xml_starttag('url') self.xml_tag('loc', url_data.url) if url_data.modified: self.xml_tag('lastmod', self.format_modified(url_data.modified, sep="T")) self.xml_tag('changefreq', self.frequency) self.xml_tag('priority', "%.2f" % priority) self.xml_endtag('url') self.flush() def end_output(self, **kwargs): """Write XML end tag.""" self.xml_endtag("urlset") self.xml_end_output() self.close_fileoutput() linkchecker-10.5.0/linkcheck/logger/sql.py000066400000000000000000000103241466565367000204640ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ A SQL logger. """ import os from . import _Logger from .. import url as urlutil def sqlify(s): """ Escape special SQL chars and strings. """ if not s: return "NULL" return "'%s'" % s.replace("'", "''").replace(os.linesep, r"\n") def intify(s): """ Coerce a truth value to 0/1. @param s: an object (usually a string) @type s: object @return: 1 if object truth value is True, else 0 @rtype: number """ if s: return 1 return 0 class SQLLogger(_Logger): """ SQL output, should work with any SQL database (not tested). """ LoggerName = 'sql' LoggerArgs = { "filename": "linkchecker-out.sql", 'separator': ';', 'dbname': 'linksdb', } def __init__(self, **kwargs): """Initialize database access data.""" args = self.get_args(kwargs) super().__init__(**args) self.init_fileoutput(args) self.dbname = args['dbname'] self.separator = args['separator'] def comment(self, s, **args): """ Write SQL comment. """ self.write("-- ") self.writeln(s=s, **args) def start_output(self): """ Write start of checking info as sql comment. """ super().start_output() if self.has_part("intro"): self.write_intro() self.writeln() self.flush() def log_url(self, url_data): """ Store url check info into the database. """ self.writeln( "insert into %(table)s(urlname," "parentname,baseref,valid,result,warning,info,url,line,col," "name,checktime,dltime,size,cached,level,modified) values (" "%(base_url)s," "%(url_parent)s," "%(base_ref)s," "%(valid)d," "%(result)s," "%(warning)s," "%(info)s," "%(url)s," "%(line)s," "%(column)s," "%(name)s," "%(checktime)d," "%(dltime)d," "%(size)d," "%(cached)d," "%(level)d," "%(modified)s" ")%(separator)s" % { 'table': self.dbname, 'base_url': sqlify(url_data.base_url), 'url_parent': sqlify(url_data.parent_url), 'base_ref': sqlify(url_data.base_ref), 'valid': intify(url_data.valid), 'result': sqlify(url_data.result), 'warning': sqlify(os.linesep.join(x[1] for x in url_data.warnings)), 'info': sqlify(os.linesep.join(url_data.info)), 'url': sqlify(urlutil.url_quote(url_data.url, encoding="utf-8")), 'line': 'NULL' if url_data.line is None else url_data.line, 'column': 'NULL' if url_data.column is None else url_data.column, 'name': sqlify(url_data.name), 'checktime': url_data.checktime, 'dltime': url_data.dltime, 'size': url_data.size, 'cached': 0, 'separator': self.separator, "level": url_data.level, "modified": sqlify(self.format_modified(url_data.modified)), } ) self.flush() def end_output(self, **kwargs): """ Write end of checking info as sql comment. """ if self.has_part("outro"): self.write_outro() self.close_fileoutput() linkchecker-10.5.0/linkcheck/logger/text.py000066400000000000000000000303761466565367000206620ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ The default text logger. """ import time from . import _Logger from .. import ansicolor, log, strformat, configuration, LOG_CHECK class TextLogger(_Logger): """ A text logger, colorizing the output if possible. Informal text output format spec: Output consists of a set of URL logs separated by one or more blank lines. A URL log consists of two or more lines. Each line consists of keyword and data, separated by whitespace. Unknown keywords will be ignored. """ LoggerName = 'text' LoggerArgs = { "filename": "linkchecker-out.txt", "wraplength": 65, 'colorparent': "default", 'colorurl': "default", 'colorname': "default", 'colorreal': "cyan", 'colorbase': "purple", 'colorvalid': "bold;green", 'colorinvalid': "bold;red", 'colorinfo': "default", 'colorwarning': "bold;yellow", 'colordltime': "default", 'colordlsize': "default", 'colorreset': "default", } def __init__(self, **kwargs): """Initialize error counter and optional file output.""" args = self.get_args(kwargs) super().__init__(**args) self.init_fileoutput(args) try: self.wraplength = int(args["wraplength"]) except ValueError: self.wraplength = self.LoggerArgs["wraplength"] log.warn(LOG_CHECK, _("Invalid value for wraplength. Using default.")) self.colorparent = args["colorparent"] self.colorurl = args["colorurl"] self.colorname = args["colorname"] self.colorreal = args["colorreal"] self.colorbase = args["colorbase"] self.colorvalid = args["colorvalid"] self.colorinvalid = args["colorinvalid"] self.colorinfo = args["colorinfo"] self.colorwarning = args["colorwarning"] self.colordltime = args["colordltime"] self.colordlsize = args["colordlsize"] self.colorreset = args["colorreset"] def init_fileoutput(self, args): """Colorize file output if possible.""" super().init_fileoutput(args) if self.fd is not None: self.fd = ansicolor.Colorizer(self.fd) def start_fileoutput(self): """Needed to make file descriptor color aware.""" init_color = self.fd is None super().start_fileoutput() if init_color: self.fd = ansicolor.Colorizer(self.fd) def start_output(self): """Write generic start checking info.""" super().start_output() if self.has_part('intro'): self.write_intro() self.flush() def write_intro(self): """Log introduction text.""" self.writeln(configuration.App) self.writeln(configuration.Copyright) self.writeln(configuration.Freeware) self.writeln( _("Read the documentation at %(url)s") % {'url': configuration.Url} ) self.writeln( _("Write comments and bugs to %(url)s") % {'url': configuration.SupportUrl} ) self.check_date() self.writeln() self.writeln(_("Start checking at %s") % strformat.strtime(self.starttime)) def log_url(self, url_data): """Write url checking info.""" self.writeln() if self.has_part('url'): self.write_url(url_data) if url_data.name and self.has_part('name'): self.write_name(url_data) if url_data.parent_url and self.has_part('parenturl'): self.write_parent(url_data) if url_data.base_ref and self.has_part('base'): self.write_base(url_data) if url_data.url and self.has_part('realurl'): self.write_real(url_data) if url_data.checktime and self.has_part('checktime'): self.write_checktime(url_data) if url_data.dltime >= 0 and self.has_part('dltime'): self.write_dltime(url_data) if url_data.size >= 0 and self.has_part('dlsize'): self.write_size(url_data) if url_data.info and self.has_part('info'): self.write_info(url_data) if url_data.modified and self.has_part('modified'): self.write_modified(url_data) if url_data.warnings and self.has_part('warning'): self.write_warning(url_data) if self.has_part('result'): self.write_result(url_data) self.flush() def write_id(self): """Write unique ID of url_data.""" self.writeln() self.write(self.part('id') + self.spaces('id')) self.writeln("%d" % self.stats.number, color=self.colorinfo) def write_url(self, url_data): """Write url_data.base_url.""" self.write(self.part('url') + self.spaces('url')) txt = strformat.strline(url_data.base_url) self.writeln(txt, color=self.colorurl) def write_name(self, url_data): """Write url_data.name.""" self.write(self.part("name") + self.spaces("name")) self.writeln(strformat.strline(url_data.name), color=self.colorname) def write_parent(self, url_data): """Write url_data.parent_url.""" self.write(self.part('parenturl') + self.spaces("parenturl")) txt = url_data.parent_url if url_data.line is not None: txt += _(", line %d") % url_data.line if url_data.column is not None: txt += _(", col %d") % url_data.column if url_data.page > 0: txt += _(", page %d") % url_data.page self.writeln(txt, color=self.colorparent) def write_base(self, url_data): """Write url_data.base_ref.""" self.write(self.part("base") + self.spaces("base")) self.writeln(url_data.base_ref, color=self.colorbase) def write_real(self, url_data): """Write url_data.url.""" self.write(self.part("realurl") + self.spaces("realurl")) self.writeln(url_data.url, color=self.colorreal) def write_dltime(self, url_data): """Write url_data.dltime.""" self.write(self.part("dltime") + self.spaces("dltime")) self.writeln(_("%.3f seconds") % url_data.dltime, color=self.colordltime) def write_size(self, url_data): """Write url_data.size.""" self.write(self.part("dlsize") + self.spaces("dlsize")) self.writeln(strformat.strsize(url_data.size), color=self.colordlsize) def write_checktime(self, url_data): """Write url_data.checktime.""" self.write(self.part("checktime") + self.spaces("checktime")) self.writeln(_("%.3f seconds") % url_data.checktime, color=self.colordltime) def write_info(self, url_data): """Write url_data.info.""" self.write(self.part("info") + self.spaces("info")) self.writeln(self.wrap(url_data.info, self.wraplength), color=self.colorinfo) def write_modified(self, url_data): """Write url_data.modified.""" self.write(self.part("modified") + self.spaces("modified")) self.writeln(self.format_modified(url_data.modified)) def write_warning(self, url_data): """Write url_data.warning.""" self.write(self.part("warning") + self.spaces("warning")) warning_msgs = [f"[{tag}] {msg}" for tag, msg in url_data.warnings] self.writeln(self.wrap(warning_msgs, self.wraplength), color=self.colorwarning) def write_result(self, url_data): """Write url_data.result.""" self.write(self.part("result") + self.spaces("result")) if url_data.valid: color = self.colorvalid self.write(_("Valid"), color=color) else: color = self.colorinvalid self.write(_("Error"), color=color) if url_data.result: self.write(": " + url_data.result, color=color) self.writeln() def write_outro(self, interrupt=False): """Write end of checking message.""" self.writeln() if interrupt: self.writeln(_("The check has been interrupted; results are not complete.")) self.write(_("That's it.") + " ") self.write(_n("%d link", "%d links", self.stats.number) % self.stats.number) self.write(" ") if self.stats.num_urls is not None: self.write( _n("in %d URL", "in %d URLs", self.stats.num_urls) % self.stats.num_urls ) self.write(_(" checked.") + " ") warning_text = ( _n("%d warning found", "%d warnings found", self.stats.warnings_printed) % self.stats.warnings_printed ) if self.stats.warnings_printed: warning_color = self.colorwarning else: warning_color = self.colorinfo self.write(warning_text, color=warning_color) if self.stats.warnings != self.stats.warnings_printed: self.write( _(" (%d ignored or duplicates not printed)") % (self.stats.warnings - self.stats.warnings_printed) ) self.write(". ") error_text = ( _n("%d error found", "%d errors found", self.stats.errors_printed) % self.stats.errors_printed ) if self.stats.errors_printed: error_color = self.colorinvalid else: error_color = self.colorvalid self.write(error_text, color=error_color) if self.stats.errors != self.stats.errors_printed: self.write( _(" (%d duplicates not printed)") % (self.stats.errors - self.stats.errors_printed) ) self.writeln(".") num = self.stats.internal_errors if num: self.writeln( _n( "There was %(num)d internal error.", "There were %(num)d internal errors.", num, ) % {"num": num} ) self.stoptime = time.time() duration = self.stoptime - self.starttime self.writeln( _("Stopped checking at %(time)s (%(duration)s)") % { "time": strformat.strtime(self.stoptime), "duration": strformat.strduration_long(duration), } ) def write_stats(self): """Write check statistic info.""" self.writeln() self.writeln(_("Statistics:")) if self.stats.downloaded_bytes is not None: self.writeln( _("Downloaded: %s.") % strformat.strsize(self.stats.downloaded_bytes) ) if self.stats.number > 0: self.writeln( _( "Content types: %(image)d image, %(text)d text, %(video)d video, " "%(audio)d audio, %(application)d application, %(mail)d mail" " and %(other)d other." ) % self.stats.link_types ) self.writeln( _("URL lengths: min=%(min)d, max=%(max)d, avg=%(avg)d.") % dict( min=self.stats.min_url_length, max=self.stats.max_url_length, avg=self.stats.avg_url_length, ) ) else: self.writeln(_("No statistics available since no URLs were checked.")) def end_output(self, **kwargs): """Write end of output info, and flush all output buffers.""" self.stats.downloaded_bytes = kwargs.get("downloaded_bytes") self.stats.num_urls = kwargs.get("num_urls") if self.has_part('stats'): self.write_stats() if self.has_part('outro'): self.write_outro(interrupt=kwargs.get("interrupt")) self.close_fileoutput() linkchecker-10.5.0/linkcheck/logger/xmllog.py000066400000000000000000000063641466565367000212000ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Base class for XML loggers. """ import xml.sax.saxutils from . import _Logger xmlattr_entities = { "&": "&", "<": "<", ">": ">", "\"": """, } def xmlquote(s): """ Quote characters for XML. """ return xml.sax.saxutils.escape(s) def xmlquoteattr(s): """ Quote XML attribute, ready for inclusion with double quotes. """ return xml.sax.saxutils.escape(s, xmlattr_entities) class _XMLLogger(_Logger): """Base class for XML output; easy to parse with any XML tool.""" def __init__(self, **kwargs): """ Initialize graph node list and internal id counter. """ args = self.get_args(kwargs) super().__init__(**args) self.init_fileoutput(args) self.indent = " " self.level = 0 def comment(self, s, **args): """ Write XML comment. """ self.write("") def xml_start_output(self): """ Write start of checking info as xml comment. """ self.writeln( '' % xmlquoteattr(self.get_charset_encoding()) ) if self.has_part("intro"): self.write_intro() self.writeln() def xml_end_output(self): """ Write end of checking info as xml comment. """ if self.has_part("outro"): self.write_outro() def xml_starttag(self, name, attrs=None): """ Write XML start tag. """ self.write(self.indent * self.level) self.write("<%s" % xmlquote(name)) if attrs: for name, value in attrs.items(): args = (xmlquote(name), xmlquoteattr(value)) self.write(' %s="%s"' % args) self.writeln(">") self.level += 1 def xml_endtag(self, name): """ Write XML end tag. """ self.level -= 1 assert self.level >= 0 self.write(self.indent * self.level) self.writeln("" % xmlquote(name)) def xml_tag(self, name, content, attrs=None): """ Write XML tag with content. """ self.write(self.indent * self.level) self.write("<%s" % xmlquote(name)) if attrs: for aname, avalue in attrs.items(): args = (xmlquote(aname), xmlquoteattr(avalue)) self.write(' %s="%s"' % args) self.writeln(f">{xmlquote(content)}") linkchecker-10.5.0/linkcheck/memoryutil.py000066400000000000000000000031401466565367000206120ustar00rootroot00000000000000# Copyright (C) 2012-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Memory utilities. """ import gc import pprint from . import strformat, log, LOG_CHECK from .fileutil import get_temp_file # Message to display when meliae package is not installed MemoryDebugMsg = strformat.format_feature_warning( module='meliae', feature='memory debugging', url='https://launchpad.net/meliae' ) def write_memory_dump(): """Dump memory to a temporary filename with the meliae package. @return: JSON filename where memory dump has been written to @rtype: string """ # first do a full garbage collection run gc.collect() if gc.garbage: log.warn(LOG_CHECK, "Unreachabe objects: %s", pprint.pformat(gc.garbage)) from meliae import scanner fo, filename = get_temp_file(mode='wb', suffix='.json', prefix='lcdump_') try: scanner.dump_all_objects(fo) finally: fo.close() return filename linkchecker-10.5.0/linkcheck/mimeutil.py000066400000000000000000000072161466565367000202410ustar00rootroot00000000000000# Copyright (C) 2005-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ File and path utilities. """ import os import re import mimetypes from . import log from .logconf import LOG_CHECK mimedb = None def init_mimedb(): """Initialize the local MIME database.""" global mimedb try: mimedb = mimetypes.MimeTypes(strict=False) except Exception as msg: log.error(LOG_CHECK, "could not initialize MIME database: %s" % msg) return # For Opera bookmark files (opera6.adr) add_mimetype(mimedb, 'text/plain', '.adr') # To recognize PHP files as HTML with content check. add_mimetype(mimedb, 'application/x-httpd-php', '.php') # To recognize WML files add_mimetype(mimedb, 'text/vnd.wap.wml', '.wml') def add_mimetype(mimedb, mimetype, extension): """Add or replace a mimetype to be used with the given extension.""" # If extension is already a common type, strict=True must be used. strict = extension in mimedb.types_map[True] mimedb.add_type(mimetype, extension, strict=strict) # if file extension lookup was unsuccessful, look at the content PARSE_CONTENTS = { "text/html": re.compile(r'^<(!DOCTYPE html|html|head|title)', re.IGNORECASE), "text/plain+opera": re.compile(r'^Opera Hotlist'), "text/plain+chromium": re.compile(r'^{\s*"checksum":'), "text/plain+linkchecker": re.compile(r'^# LinkChecker URL list', re.IGNORECASE), "application/xml+sitemapindex": re.compile(r'(<\?xml[^<]+)? [name](http://link.com "Optional title") [id]: http://link.com "Optional title" """ # Some ideas and code were borrowed from https://pypi.python.org/pypi/markdown2 project import re from . import _ContentPlugin from .. import log, LOG_PLUGIN class MarkdownCheck(_ContentPlugin): """Markdown parsing plugin.""" _filename_re_key = "filename_re" _default_filename_re = re.compile(r'.*\.(markdown|md(own)?|mkdn?)$') _link_res = [ re.compile(r'<((https?|ftp):[^\'">\s]+)>', re.I), re.compile( r""" \[.+\]: # id [ \t]*\n? # maybe *one* newline [ \t]* ? # url = \1 [ \t]* (?: \n? # maybe one newline [ \t]* (?<=\s) # lookbehind for whitespace ['"(] [^\n]* # title ['")] [ \t]* )? # title is optional (?:\n+|\Z) """, re.X | re.M | re.U, ), ] _whitespace = re.compile(r'\s*') _strip_anglebrackets = re.compile(r'<(.*)>.*') _inline_link_title = re.compile( r''' ( # \1 [ \t]+ (['"]) # quote char (.*?) )? # title is optional \)$ ''', re.X | re.S, ) def __init__(self, config): super().__init__(config) self.filename_re = self._default_filename_re pattern = config.get(self._filename_re_key) if pattern: try: self.filename_re = re.compile(pattern) except re.error as msg: log.warn(LOG_PLUGIN, _("Invalid regex pattern %r: %s"), pattern, msg) @classmethod def read_config(cls, configparser): """Read configuration file options.""" config = dict() config[cls._filename_re_key] = ( configparser.get(cls.__name__, cls._filename_re_key) if configparser.has_option(cls.__name__, cls._filename_re_key) else None ) return config def applies_to(self, url_data, pagetype=None): """Check for Markdown file.""" return self.filename_re.search(url_data.base_url) is not None def check(self, url_data): """Extracts urls from the file.""" content = url_data.get_content() self._check_by_re(url_data, content) self._check_inline_links(url_data, content) def _save_url(self, url_data, content, url_text, url_pos): """Saves url. Converts url to 1-line text and url position as offset from the file beginning to (line, column). :param url_data: object for url storing :param content: file content :param url_text: url text :param url_pos: url position from the beginning """ line = content.count('\n', 0, url_pos) + 1 column = url_pos - content.rfind('\n', 0, url_pos) url_data.add_url( url_text.translate(str.maketrans("", "", '\n ')), line=line, column=column ) def _check_by_re(self, url_data, content): """ Finds urls by re. :param url_data: object for url storing :param content: file content """ for link_re in self._link_res: for u in link_re.finditer(content): self._save_url(url_data, content, u.group(1), u.start(1)) def _find_balanced(self, text, start, open_c, close_c): """Returns the index where the open_c and close_c characters balance out - the same number of open_c and close_c are encountered - or the end of string if it's reached before the balance point is found. """ i = start n = len(text) count = 1 while count > 0 and i < n: if text[i] == open_c: count += 1 elif text[i] == close_c: count -= 1 i += 1 return i def _extract_url_and_title(self, text, start): """Extracts the url from the tail of a link.""" # text[start] equals the opening parenthesis idx = self._whitespace.match(text, start + 1).end() if idx == len(text): return None, None end_idx = idx has_anglebrackets = text[idx] == "<" if has_anglebrackets: end_idx = self._find_balanced(text, end_idx + 1, "<", ">") end_idx = self._find_balanced(text, end_idx, "(", ")") match = self._inline_link_title.search(text, idx, end_idx) if not match: return None, None url = text[idx:match.start()] if has_anglebrackets: url = self._strip_anglebrackets.sub(r'\1', url) return url, end_idx def _check_inline_links(self, url_data, content): """Checks inline links. :param url_data: url_data object :param content: content for processing """ MAX_LINK_TEXT_SENTINEL = 3000 curr_pos = 0 content_length = len(content) while True: # Handle the next link. # The next '[' is the start of: # - an inline anchor: [text](url "title") # - an inline img: ![text](url "title") # - not markup: [...anything else... try: start_idx = content.index('[', curr_pos) except ValueError: break # Find the matching closing ']'. bracket_depth = 0 for p in range( start_idx + 1, min(start_idx + MAX_LINK_TEXT_SENTINEL, content_length) ): if content[p] == ']': bracket_depth -= 1 if bracket_depth < 0: break elif content[p] == '[': bracket_depth += 1 else: # Closing bracket not found within sentinel length. This isn't markup. curr_pos = start_idx + 1 continue # Now determine what this is by the remainder. p += 1 if p >= content_length: return if content[p] == '(': url, url_end_idx = self._extract_url_and_title(content, p) if url is not None: self._save_url(url_data, content, url, p) start_idx = url_end_idx # Otherwise, it isn't markup. curr_pos = start_idx + 1 linkchecker-10.5.0/linkcheck/plugins/parsepdf.py000066400000000000000000000062571466565367000217050ustar00rootroot00000000000000# Copyright (C) 2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Parse links in PDF files with pdfminer. """ from io import BytesIO from . import _ParserPlugin try: from pdfminer.pdfparser import PDFParser from pdfminer.pdfdocument import PDFDocument from pdfminer.pdftypes import PDFStream, PDFObjRef from pdfminer.pdfpage import PDFPage from pdfminer.psparser import PSException except ImportError: has_pdflib = False else: has_pdflib = True from .. import log, LOG_PLUGIN def search_url(obj, url_data, pageno, seen_objs): """Recurse through a PDF object, searching for URLs.""" if isinstance(obj, PDFObjRef): if obj.objid in seen_objs: # prevent recursive loops return seen_objs.add(obj.objid) obj = obj.resolve() if isinstance(obj, dict): for key, value in obj.items(): if key == 'URI': url_data.add_url(value.decode("ascii"), page=pageno) else: search_url(value, url_data, pageno, seen_objs) elif isinstance(obj, list): for elem in obj: search_url(elem, url_data, pageno, seen_objs) elif isinstance(obj, PDFStream): search_url(obj.attrs, url_data, pageno, seen_objs) class PdfParser(_ParserPlugin): """PDF parsing plugin.""" def __init__(self, config): """Check for pdfminer.""" if not has_pdflib: log.warn(LOG_PLUGIN, "pdfminer not found for PdfParser plugin") super().__init__(config) def applies_to(self, url_data, pagetype=None): """Check for PDF pagetype.""" return has_pdflib and pagetype == 'pdf' def check(self, url_data): """Parse PDF data.""" # XXX user authentication from url_data password = '' data = url_data.get_raw_content() # PDFParser needs a seekable file object fp = BytesIO(data) try: parser = PDFParser(fp) doc = PDFDocument(parser, password=password) for (pageno, page) in enumerate(PDFPage.create_pages(doc), start=1): if "Contents" in page.attrs: search_url(page.attrs["Contents"], url_data, pageno, set()) if "Annots" in page.attrs: search_url(page.attrs["Annots"], url_data, pageno, set()) except PSException as msg: if not msg.args: # at least show the class name msg = repr(msg) log.warn(LOG_PLUGIN, "Error parsing PDF file: %s", msg) linkchecker-10.5.0/linkcheck/plugins/parseword.py000066400000000000000000000125051466565367000221000ustar00rootroot00000000000000# Copyright (C) 2010-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Parse hyperlinks in Word files. """ from . import _ParserPlugin try: import win32com import pythoncom has_win32com = True Error = pythoncom.com_error except ImportError: has_win32com = False Error = Exception from .. import fileutil, log, LOG_PLUGIN _initialized = False def init_win32com(): """Initialize the win32com.client cache.""" global _initialized if _initialized: return import win32com.client if win32com.client.gencache.is_readonly: # allow gencache to create the cached wrapper objects win32com.client.gencache.is_readonly = False # under py2exe the call in gencache to __init__() does not happen # so we use Rebuild() to force the creation of the gen_py folder # Note that the python...\win32com.client.gen_py dir must not exist # to allow creation of the cache in %temp% for py2exe. # This is ensured by excluding win32com.gen_py in setup.py win32com.client.gencache.Rebuild() _initialized = True def has_word(): """Determine if Word is available on the current system.""" if not has_win32com: return False try: import _winreg as winreg except ImportError: import winreg try: key = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, "Word.Application") winreg.CloseKey(key) return True except (OSError, ImportError): pass return False def constants(name): """Helper to return constants. Avoids importing win32com.client in other modules.""" return getattr(win32com.client.constants, name) def get_word_app(): """Return open Word.Application handle, or None if Word is not available on this system.""" if not has_word(): return None # Since this function is called from different threads, initialize # the COM layer. pythoncom.CoInitialize() import win32com.client app = win32com.client.gencache.EnsureDispatch("Word.Application") app.Visible = False return app def close_word_app(app): """Close Word application object.""" app.Quit() def open_wordfile(app, filename): """Open given Word file with application object.""" return app.Documents.Open( filename, ReadOnly=True, AddToRecentFiles=False, Visible=False, NoEncodingDialog=True, ) def close_wordfile(doc): """Close word file.""" doc.Close() class WordParser(_ParserPlugin): """Word parsing plugin.""" def __init__(self, config): """Check for Word.""" init_win32com() if not has_word(): log.warn(LOG_PLUGIN, "Microsoft Word not found for WordParser plugin") super().__init__(config) def applies_to(self, url_data, pagetype=None): """Check for Word pagetype.""" return has_word() and pagetype == 'word' def check(self, url_data): """Parse Word data.""" content = url_data.get_raw_content() filename = get_temp_filename(content) # open word file and parse hyperlinks try: app = get_word_app() try: doc = open_wordfile(app, filename) if doc is None: raise Error("could not open word file %r" % filename) try: for link in doc.Hyperlinks: line = get_line_number(doc, link.Range) name = link.TextToDisplay url_data.add_url(link.Address, name=name, line=line) finally: close_wordfile(doc) finally: close_word_app(app) except Error as msg: log.warn(LOG_PLUGIN, "Error parsing word file: %s", msg) def get_line_number(doc, wrange): """Get line number for given range object.""" lineno = 1 wrange.Select() wdFirstCharacterLineNumber = constants("wdFirstCharacterLineNumber") wdGoToLine = constants("wdGoToLine") wdGoToPrevious = constants("wdGoToPrevious") while True: curline = doc.Selection.Information(wdFirstCharacterLineNumber) doc.Selection.GoTo(wdGoToLine, wdGoToPrevious, Count=1, Name="") lineno += 1 prevline = doc.Selection.Information(wdFirstCharacterLineNumber) if prevline == curline: break return lineno def get_temp_filename(content): """Get temporary filename for content to parse.""" # store content in temporary file fd, filename = fileutil.get_temp_file(mode='wb', suffix='.doc', prefix='lc_') try: fd.write(content) finally: fd.close() return filename linkchecker-10.5.0/linkcheck/plugins/regexcheck.py000066400000000000000000000056241466565367000222060ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Check page content with regular expression. """ import re from . import _ContentPlugin from .. import log, LOG_PLUGIN class RegexCheck(_ContentPlugin): """Define a regular expression which prints a warning if it matches any content of the checked link. This applies only to valid pages, so we can get their content. Use this to check for pages that contain some form of error message, for example 'This page has moved' or 'Oracle Application error'. Note that multiple values can be combined in the regular expression, for example "(This page has moved|Oracle Application error)".""" def __init__(self, config): """Set warning regex from config.""" super().__init__(config) self.warningregex = None pattern = config["warningregex"] if pattern: try: self.warningregex = re.compile(pattern) except re.error as msg: log.warn(LOG_PLUGIN, _("Invalid regex pattern %r: %s"), pattern, msg) def applies_to(self, url_data): """Check for warningregex, extern flag and parseability.""" return self.warningregex and not url_data.extern[0] and url_data.is_parseable() def check(self, url_data): """Check content.""" log.debug(LOG_PLUGIN, "checking content for warning regex") content = url_data.get_content() # add warnings for found matches, up to the maximum allowed number match = self.warningregex.search(content) if match: # calculate line number for match line = content.count('\n', 0, match.start()) # add a warning message msg = _("Found %(match)r at line %(line)d in link contents.") url_data.add_warning(msg % {"match": match.group(), "line": line}) @classmethod def read_config(cls, configparser): """Read configuration file options.""" config = dict() section = cls.__name__ option = "warningregex" if configparser.has_option(section, option): value = configparser.get(section, option) else: value = None config[option] = value return config linkchecker-10.5.0/linkcheck/plugins/sslcertcheck.py000066400000000000000000000111371466565367000225470ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Handle https links. """ import time import threading from . import _ConnectionPlugin from .. import strformat, LinkCheckerError from ..decorators import synchronized _lock = threading.Lock() # configuration option names sslcertwarndays = "sslcertwarndays" class SslCertificateCheck(_ConnectionPlugin): """Check SSL certificate expiration date. Only internal https: links will be checked. A domain will only be checked once to avoid duplicate warnings. The expiration warning time can be configured with the sslcertwarndays option.""" def __init__(self, config): """Initialize plugin.""" super().__init__(config) self.warn_ssl_cert_secs_valid = ( config[sslcertwarndays] * strformat.SECONDS_PER_DAY ) # do not check hosts multiple times self.checked_hosts = set() def applies_to(self, url_data): """Check validity, scheme, extern and url_connection.""" return ( url_data.valid and url_data.scheme == 'https' and not url_data.extern[0] and url_data.url_connection is not None ) @synchronized(_lock) def check(self, url_data): """Run all SSL certificate checks that have not yet been done. OpenSSL already checked the SSL notBefore and notAfter dates. """ host = url_data.urlparts[1] if host in self.checked_hosts: return self.checked_hosts.add(host) cert = url_data.ssl_cert config = url_data.aggregate.config if cert and 'notAfter' in cert: self.check_ssl_valid_date(url_data, cert) elif config['sslverify']: msg = _('certificate did not include "notAfter" information') url_data.add_warning(msg) else: msg = _('SSL verification is disabled; enable the sslverify option') url_data.add_warning(msg) def check_ssl_valid_date(self, url_data, cert): """Check if the certificate is still valid, or if configured check if it's at least a number of days valid. """ import ssl try: notAfter = ssl.cert_time_to_seconds(cert['notAfter']) except ValueError as msg: msg = _('Invalid SSL certificate "notAfter" value %r') % cert['notAfter'] url_data.add_warning(msg) return curTime = time.time() # Calculate seconds until certificate expires. Can be negative if # the certificate is already expired. secondsValid = notAfter - curTime args = dict(expire=cert['notAfter']) if secondsValid < 0: msg = _('SSL certificate is expired on %(expire)s.') url_data.add_warning(msg % args) else: args['valid'] = strformat.strduration_long(secondsValid) if secondsValid < self.warn_ssl_cert_secs_valid: msg = _( 'SSL certificate expires on %(expire)s and is only %(valid)s valid.' ) url_data.add_warning(msg % args) else: msg = _('SSL certificate expires on %(expire)s and is %(valid)s valid.') url_data.add_info(msg % args) @classmethod def read_config(cls, configparser): """Read configuration file options.""" config = dict() section = cls.__name__ option = sslcertwarndays if configparser.has_option(section, option): num = configparser.getint(section, option) if num > 0: config[option] = num else: msg = _("invalid value for %s: %d must not be less than %d") % ( option, num, 0, ) raise LinkCheckerError(msg) else: # set the default config[option] = 30 return config linkchecker-10.5.0/linkcheck/plugins/syntaxchecks.py000066400000000000000000000127211466565367000226010ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. import threading import time import requests from xml.dom.minidom import parseString from . import _ContentPlugin from .. import log, LOG_PLUGIN from ..decorators import synchronized _w3_time_lock = threading.Lock() class W3Timer: """Ensure W3C apis are not hammered.""" # every X seconds SleepSeconds = 2 def __init__(self): """Remember last API call.""" self.last_w3_call = 0 @synchronized(_w3_time_lock) def check_w3_time(self): """Make sure the W3C validators are at most called once a second.""" if time.time() - self.last_w3_call < W3Timer.SleepSeconds: time.sleep(W3Timer.SleepSeconds) self.last_w3_call = time.time() class HtmlSyntaxCheck(_ContentPlugin): """Check the syntax of HTML pages with the online W3C HTML validator. See https://validator.w3.org/docs/api.html. """ def __init__(self, config): """Initialize plugin.""" super().__init__(config) self.timer = W3Timer() log.warn( LOG_PLUGIN, _("HTML syntax check plugin is broken. Fixes welcome.") ) def applies_to(self, url_data): """Check for HTML, extern and session.""" return False # XXX Plugin disabled return (url_data.is_html() and not url_data.extern[0] and hasattr(url_data, "session")) def check(self, url_data): """Check HTML syntax of given URL.""" self.timer.check_w3_time() session = url_data.session try: body = {'uri': url_data.url, 'output': 'soap12'} response = session.post('https://validator.w3.org/check', data=body) response.raise_for_status() if response.headers.get('x-w3c-validator-status', 'Invalid') == 'Valid': url_data.add_info("W3C Validator: %s" % _("valid HTML syntax")) return check_w3_errors(url_data, response.text, "W3C HTML") except requests.exceptions.RequestException: pass # ignore service failures except Exception as msg: log.warn( LOG_PLUGIN, _("HTML syntax check plugin error: %(msg)s ") % {"msg": msg} ) class CssSyntaxCheck(_ContentPlugin): """Check the syntax of CSS stylesheets with the online W3C CSS validator. See https://jigsaw.w3.org/css-validator/manual.html#expert. """ def __init__(self, config): """Initialize plugin.""" super().__init__(config) self.timer = W3Timer() def applies_to(self, url_data): """Check for CSS, extern and session.""" return (url_data.is_css() and not url_data.extern[0] and hasattr(url_data, "session")) def check(self, url_data): """Check CSS syntax of given URL.""" self.timer.check_w3_time() session = url_data.session try: url = 'https://jigsaw.w3.org/css-validator/validator' params = { 'uri': url_data.url, 'warning': '2', 'output': 'soap12', } response = session.get(url, params=params) response.raise_for_status() if response.headers.get('X-W3C-Validator-Status', 'Invalid') == 'Valid': url_data.add_info("W3C Validator: %s" % _("valid CSS syntax")) return check_w3_errors(url_data, response.text, "W3C CSS") except requests.exceptions.RequestException: pass # ignore service failures except Exception as msg: log.warn( LOG_PLUGIN, _("CSS syntax check plugin error: %(msg)s ") % {"msg": msg} ) def check_w3_errors(url_data, xml, w3type): """Add warnings for W3C HTML or CSS errors in xml format. w3type is either "W3C HTML" or "W3C CSS".""" dom = parseString(xml) for error in dom.getElementsByTagName('m:error'): if w3type == "W3C HTML": warnmsg = _( "%(w3type)s validation error at line %(line)s col %(column)s: %(msg)s" ) else: warnmsg = _( "%(w3type)s validation error at line %(line)s: %(msg)s" ) attrs = { "w3type": w3type, "line": getXmlText(error, "m:line"), "msg": getXmlText(error, "m:message"), } if w3type == "W3C HTML": attrs["column"] = getXmlText(error, "m:col") url_data.add_warning(warnmsg % attrs) def getXmlText(parent, tag): """Return XML content of given tag in parent element.""" elem = parent.getElementsByTagName(tag)[0] # Yes, the DOM standard is awful. rc = [] for node in elem.childNodes: if node.nodeType == node.TEXT_NODE: rc.append(node.data) return ''.join(rc) linkchecker-10.5.0/linkcheck/plugins/viruscheck.py000066400000000000000000000172411466565367000222420ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Check page content for virus infection with clamav. """ import os import socket from . import _ContentPlugin from .. import log, LOG_PLUGIN from ..socketutil import create_socket class VirusCheck(_ContentPlugin): """Checks the page content for virus infections with clamav. A local clamav daemon must be installed.""" def __init__(self, config): """Initialize clamav configuration.""" super().__init__(config) # XXX read config self.clamav_conf = get_clamav_conf(canonical_clamav_conf()) if not self.clamav_conf: log.warn(LOG_PLUGIN, "clamav daemon not found for VirusCheck plugin") def applies_to(self, url_data): """Check for clamav and extern.""" return self.clamav_conf and not url_data.extern[0] def check(self, url_data): """Scan content for viruses.""" data = url_data.get_raw_content() infected, errors = scan(data, self.clamav_conf) if infected or errors: for msg in infected: url_data.add_warning("Virus scan infection: %s" % msg) for msg in errors: url_data.add_warning("Virus scan error: %s" % msg) else: url_data.add_info("No viruses in data found.") @classmethod def read_config(cls, configparser): """Read configuration file options.""" config = dict() section = cls.__name__ option = "clamavconf" if configparser.has_option(section, option): value = configparser.get(section, option) else: value = None config[option] = value return config class ClamavError(Exception): """Raised on clamav errors.""" pass class ClamdScanner: """Virus scanner using a clamd daemon process.""" def __init__(self, clamav_conf): """Initialize clamd daemon process sockets.""" self.infected = [] self.errors = [] self.sock, self.host = clamav_conf.new_connection() self.sock_rcvbuf = self.sock.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF) self.wsock = self.new_scansock() def new_scansock(self): """Return a connected socket for sending scan data to it.""" port = None try: self.sock.sendall(b"STREAM") port = None for dummy in range(60): data = self.sock.recv(self.sock_rcvbuf) i = data.find(b"PORT") if i != -1: port = int(data[i + 5:]) break except OSError: self.sock.close() raise if port is None: raise ClamavError(_("clamd is not ready for stream scanning")) sockinfo = get_sockinfo(self.host, port=port) wsock = create_socket(socket.AF_INET, socket.SOCK_STREAM) try: wsock.connect(sockinfo[0][4]) except OSError: wsock.close() raise return wsock def scan(self, data): """Scan given data for viruses.""" self.wsock.sendall(data) def close(self): """Get results and close clamd daemon sockets.""" self.wsock.close() data = self.sock.recv(self.sock_rcvbuf) while data: if b"FOUND\n" in data: self.infected.append(data.decode('UTF-8', 'replace')) if b"ERROR\n" in data: self.errors.append(data.decode('UTF-8', 'replace')) data = self.sock.recv(self.sock_rcvbuf) self.sock.close() def canonical_clamav_conf(): """Default clamav configs for various platforms.""" if os.name == 'posix': clamavconf = "/etc/clamav/clamd.conf" elif os.name == 'nt': clamavconf = r"c:\clamav-devel\etc\clamd.conf" else: clamavconf = "clamd.conf" return clamavconf def get_clamav_conf(filename): """Initialize clamav configuration.""" if os.path.isfile(filename): return ClamavConfig(filename) log.warn(LOG_PLUGIN, "No ClamAV config file found at %r.", filename) def get_sockinfo(host, port=None): """Return socket.getaddrinfo for given host and port.""" family, socktype = socket.AF_INET, socket.SOCK_STREAM return socket.getaddrinfo(host, port, family, socktype) class ClamavConfig(dict): """Clamav configuration wrapper, with clamd connection method.""" def __init__(self, filename): """Parse clamav configuration file.""" super().__init__() self.parseconf(filename) if self.get('ScannerDaemonOutputFormat'): raise ClamavError(_("ScannerDaemonOutputFormat must be disabled")) if self.get('TCPSocket') and self.get('LocalSocket'): raise ClamavError( _("only one of TCPSocket and LocalSocket must be enabled") ) def parseconf(self, filename): """Parse clamav configuration from given file.""" with open(filename) as fd: # yet another config format, sigh for line in fd: line = line.strip() if not line or line.startswith("#"): # ignore empty lines and comments continue split = line.split(None, 1) if len(split) == 1: self[split[0]] = True else: self[split[0]] = split[1] def new_connection(self): """Connect to clamd for stream scanning. @return: tuple (connected socket, host) """ if self.get('LocalSocket'): host = 'localhost' sock = self.create_local_socket() elif self.get('TCPSocket'): host = self.get('TCPAddr', 'localhost') sock = self.create_tcp_socket(host) else: raise ClamavError(_("one of TCPSocket or LocalSocket must be enabled")) return sock, host def create_local_socket(self): """Create local socket, connect to it and return socket object.""" sock = create_socket(socket.AF_UNIX, socket.SOCK_STREAM) addr = self['LocalSocket'] try: sock.connect(addr) except OSError: sock.close() raise return sock def create_tcp_socket(self, host): """Create tcp socket, connect to it and return socket object.""" port = int(self['TCPSocket']) sockinfo = get_sockinfo(host, port=port) sock = create_socket(socket.AF_INET, socket.SOCK_STREAM) try: sock.connect(sockinfo[0][4]) except OSError: sock.close() raise return sock def scan(data, clamconf): """Scan data for viruses. @return: (infection msgs, errors) @rtype: ([], []) """ try: scanner = ClamdScanner(clamconf) except OSError: errmsg = _("Could not connect to ClamAV daemon.") return ([], [errmsg]) try: scanner.scan(data) finally: scanner.close() return scanner.infected, scanner.errors linkchecker-10.5.0/linkcheck/robotparser2.py000066400000000000000000000333071466565367000210400ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Robots.txt parser. The robots.txt Exclusion Protocol is implemented as specified in https://www.robotstxt.org/norobots-rfc.txt """ import time import urllib.parse import requests from . import log, LOG_CHECK, configuration __all__ = ["RobotFileParser"] ACCEPT_ENCODING = 'x-gzip,gzip,deflate' class RobotFileParser: """This class provides a set of methods to read, parse and answer questions about a single robots.txt file.""" def __init__(self, session, url='', auth=None, timeout=None): """Initialize internal entry lists and store given url and credentials.""" self.set_url(url) self.session = session self.auth = auth self.timeout = timeout self._reset() def _reset(self): """Reset internal flags and entry lists.""" self.entries = [] self.default_entry = None self.disallow_all = False self.allow_all = False self.last_checked = 0 # list of tuples (sitemap url, line number) self.sitemap_urls = [] self.encoding = None def mtime(self): """Returns the time the robots.txt file was last fetched. This is useful for long-running web spiders that need to check for new robots.txt files periodically. @return: last modified in time.time() format @rtype: number """ return self.last_checked def modified(self): """Set the time the robots.txt file was last fetched to the current time.""" self.last_checked = time.time() def set_url(self, url): """Set the URL referring to a robots.txt file.""" self.url = url self.host, self.path = urllib.parse.urlparse(url)[1:3] def read(self): """Read the robots.txt URL and feeds it to the parser.""" self._reset() kwargs = dict( headers={ 'User-Agent': configuration.UserAgent, 'Accept-Encoding': ACCEPT_ENCODING, } ) if self.auth: kwargs["auth"] = self.auth if self.timeout: kwargs["timeout"] = self.timeout try: response = self.session.get(self.url, **kwargs) response.raise_for_status() log.debug(LOG_CHECK, "Robots response headers: %s", response.headers) content_type = response.headers.get('content-type') self.encoding = response.encoding = "utf-8" if content_type and content_type.lower().startswith('text/plain'): self.parse(response.iter_lines(decode_unicode=True)) else: log.debug(LOG_CHECK, "%r allow all (no text content)", self.url) self.allow_all = True except requests.HTTPError as x: if x.response.status_code in (401, 403): self.disallow_all = True log.debug( LOG_CHECK, "%r disallow all (code %d)", self.url, x.response.status_code, ) else: self.allow_all = True log.debug(LOG_CHECK, "%r allow all (HTTP error)", self.url) except requests.exceptions.Timeout: raise except requests.exceptions.RequestException: # no network or other failure self.allow_all = True log.debug(LOG_CHECK, "%r allow all (request error)", self.url) def _add_entry(self, entry): """Add a parsed entry to entry list. @return: None """ if "*" in entry.useragents: # the default entry is considered last self.default_entry = entry else: self.entries.append(entry) def parse(self, lines): """Parse the input lines from a robot.txt file. We allow that a user-agent: line is not preceded by one or more blank lines. @return: None """ log.debug(LOG_CHECK, "%r parse lines", self.url) state = 0 linenumber = 0 entry = Entry() for line in lines: line = line.strip() linenumber += 1 if not line: if state == 1: log.debug( LOG_CHECK, "%r line %d: allow or disallow directives without any" " user-agent line", self.url, linenumber, ) entry = Entry() state = 0 elif state == 2: self._add_entry(entry) entry = Entry() state = 0 # remove optional comment and strip line i = line.find('#') if i >= 0: line = line[:i] line = line.strip() if not line: continue line = line.split(':', 1) if len(line) == 2: line[0] = line[0].strip().lower() line[1] = urllib.parse.unquote(line[1].strip(), self.encoding) if line[0] == "user-agent": if state == 2: log.debug( LOG_CHECK, "%r line %d: missing blank line before" " user-agent directive", self.url, linenumber, ) self._add_entry(entry) entry = Entry() entry.useragents.append(line[1]) state = 1 elif line[0] == "disallow": if state == 0: log.debug( LOG_CHECK, "%r line %d: missing user-agent directive before this line", self.url, linenumber, ) else: entry.rulelines.append(RuleLine(line[1], False)) state = 2 elif line[0] == "allow": if state == 0: log.debug( LOG_CHECK, "%r line %d: missing user-agent directive before this line", self.url, linenumber, ) else: entry.rulelines.append(RuleLine(line[1], True)) state = 2 elif line[0] == "crawl-delay": if state == 0: log.debug( LOG_CHECK, "%r line %d: missing user-agent directive before this line", self.url, linenumber, ) else: try: entry.crawldelay = max(0, int(line[1])) state = 2 except (ValueError, OverflowError): log.debug( LOG_CHECK, "%r line %d: invalid delay number %r", self.url, linenumber, line[1], ) elif line[0] == "sitemap": # Note that sitemap URLs must be absolute according to # http://www.sitemaps.org/protocol.html#submit_robots # But this should be checked by the calling layer. self.sitemap_urls.append((line[1], linenumber)) else: log.debug( LOG_CHECK, "%r line %d: unknown key %r", self.url, linenumber, line[0], ) else: log.debug( LOG_CHECK, "%r line %d: malformed line %r", self.url, linenumber, line, ) if state in (1, 2): self.entries.append(entry) self.modified() log.debug(LOG_CHECK, "Parsed rules:\n%s", str(self)) def can_fetch(self, useragent, url): """Using the parsed robots.txt decide if useragent can fetch url. @return: True if agent can fetch url, else False @rtype: bool """ log.debug( LOG_CHECK, "%r check allowance for:\n user agent: %r\n url: %r ...", self.url, useragent, url, ) if self.disallow_all: log.debug(LOG_CHECK, " ... disallow all.") return False if self.allow_all: log.debug(LOG_CHECK, " ... allow all.") return True # search for given user agent matches # the first match counts url = ( urllib.parse.quote(urllib.parse.urlparse(urllib.parse.unquote(url))[2]) or "/" ) for entry in self.entries: if entry.applies_to(useragent): return entry.allowance(url) # try the default entry last if self.default_entry is not None: return self.default_entry.allowance(url) # agent not found ==> access granted log.debug(LOG_CHECK, " ... agent not found, allow.") return True def get_crawldelay(self, useragent): """Look for a configured crawl delay. @return: crawl delay in seconds or zero @rtype: integer >= 0 """ for entry in self.entries: if entry.applies_to(useragent): return entry.crawldelay return 0 def __str__(self): """Constructs string representation, usable as contents of a robots.txt file. @return: robots.txt format @rtype: string """ lines = [str(entry) for entry in self.entries] if self.default_entry is not None: lines.append(str(self.default_entry)) return "\n\n".join(lines) class RuleLine: """A rule line is a single "Allow:" (allowance==1) or "Disallow:" (allowance==0) followed by a path. """ def __init__(self, path, allowance): """Initialize with given path and allowance info.""" if path == '' and not allowance: # an empty value means allow all allowance = True path = '/' self.path = urllib.parse.quote(path) self.allowance = allowance def applies_to(self, path): """Look if given path applies to this rule. @return: True if pathname applies to this rule, else False @rtype: bool """ return self.path == "*" or path.startswith(self.path) def __str__(self): """Construct string representation in robots.txt format. @return: robots.txt format @rtype: string """ return ("Allow" if self.allowance else "Disallow") + ": " + self.path class Entry: """An entry has one or more user-agents and zero or more rulelines.""" def __init__(self): """Initialize user agent and rule list.""" self.useragents = [] self.rulelines = [] self.crawldelay = 0 def __str__(self): """string representation in robots.txt format. @return: robots.txt format @rtype: string """ lines = ["User-agent: %s" % agent for agent in self.useragents] if self.crawldelay: lines.append("Crawl-delay: %d" % self.crawldelay) lines.extend([str(line) for line in self.rulelines]) return "\n".join(lines) def applies_to(self, useragent): """Check if this entry applies to the specified agent. @return: True if this entry applies to the agent, else False. @rtype: bool """ if not useragent: return True useragent = useragent.lower() for agent in self.useragents: if agent == '*': # we have the catch-all agent return True if agent.lower() in useragent: return True return False def allowance(self, filename): """Preconditions: - our agent applies to this entry - filename is URL decoded Check if given filename is allowed to access this entry. @return: True if allowed, else False @rtype: bool """ for line in self.rulelines: log.debug(LOG_CHECK, "%s %s %s", filename, str(line), line.allowance) if line.applies_to(filename): log.debug(LOG_CHECK, " ... rule line %s", line) return line.allowance log.debug( LOG_CHECK, " ... no rule lines of %s applied to %s; allowed.", self.useragents, filename, ) return True linkchecker-10.5.0/linkcheck/socketutil.py000066400000000000000000000040301466565367000205710ustar00rootroot00000000000000# Copyright (C) 2008-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. import socket # test for IPv6, both in Python build and in kernel build has_ipv6 = False if socket.has_ipv6: # python has ipv6 compiled in, but the operating system also # has to support it. try: socket.socket(socket.AF_INET6, socket.SOCK_STREAM).close() has_ipv6 = True except OSError as msg: # only catch these one: # socket.error: (97, 'Address family not supported by protocol') # socket.error: (10047, 'Address family not supported by protocol') # socket.error: (43, 'Protocol not supported') if msg.args[0] not in (97, 10047, 43): raise def create_socket(family, socktype, proto=0, timeout=60): """ Create a socket with given family and type. If SSL context is given an SSL socket is created. """ sock = socket.socket(family, socktype, proto=proto) sock.settimeout(timeout) socktypes_inet = [socket.AF_INET] if has_ipv6: socktypes_inet.append(socket.AF_INET6) if family in socktypes_inet and socktype == socket.SOCK_STREAM: # disable NAGLE algorithm, which means sending pending data # immediately, possibly wasting bandwidth but improving # responsiveness for fast networks sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) return sock linkchecker-10.5.0/linkcheck/strformat.py000066400000000000000000000174411466565367000204360ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. # # Some functions have been taken and adjusted from the quodlibet # source. Quodlibet is (C) 2004-2005 Joe Wreschnig, Michael Urman # and licensed under the GNU General Public License version 2. """ Various string utility functions. Note that these functions are not necessarily optimised for large strings, so use with care. """ import math import re import textwrap import os import time import locale import pydoc # some handy time constants SECONDS_PER_MINUTE = 60 SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR def ascii_safe(s): """Get ASCII string without raising encoding errors. Unknown characters of the given encoding will be ignored. @param s: the string to be encoded @type s: string or None @return: version of s containing only ASCII characters, or None if s was None @rtype: string or None """ if s: s = s.encode('ascii', 'ignore').decode('ascii') return s def unquote(s, matching=False): """Remove leading and ending single and double quotes. The quotes need to match if matching is True. Only one quote from each end will be stripped. @return: if s evaluates to False, return s as is, else return string with stripped quotes @rtype: unquoted string, or s unchanged if it is evaluating to False """ if not s: return s if len(s) < 2: return s if matching: if s[0] in ("\"'") and s[0] == s[-1]: s = s[1:-1] else: if s[0] in ("\"'"): s = s[1:] if s[-1] in ("\"'"): s = s[:-1] return s _para_mac = r"(?:{sep})(?:(?:{sep})\s*)+".format(sep='\r') _para_posix = r"(?:{sep})(?:(?:{sep})\s*)+".format(sep='\n') _para_win = r"(?:{sep})(?:(?:{sep})\s*)+".format(sep='\r\n') _para_ro = re.compile(f"{_para_mac}|{_para_posix}|{_para_win}") def get_paragraphs(text): """A new paragraph is considered to start at a line which follows one or more blank lines (lines containing nothing or just spaces). The first line of the text also starts a paragraph.""" if not text: return [] return _para_ro.split(text) def wrap(text, width, **kwargs): """Adjust lines of text to be not longer than width. The text will be returned unmodified if width <= 0. See textwrap.wrap() for a list of supported kwargs. Returns text with lines no longer than given width.""" if width <= 0 or not text: return text ret = [] for para in get_paragraphs(text): text = " ".join(para.strip().split()) ret.extend(textwrap.wrap(text, width, **kwargs)) return os.linesep.join(ret) def indent(text, indent_string=" "): """Indent each line of text with the given indent string.""" return os.linesep.join(f"{indent_string}{x}" for x in text.splitlines()) def paginate(text): """Print text in pages of lines.""" pydoc.pager(text) def strsize(b, grouping=True): """Return human representation of bytes b. A negative number of bytes raises a value error.""" if b < 0: raise ValueError("Invalid negative byte number") if b < 1024: return "%sB" % locale.format_string("%d", b, grouping) if b < 1024 * 10: return "%sKB" % locale.format_string("%d", (b // 1024), grouping) if b < 1024 * 1024: return "%sKB" % locale.format_string("%.2f", (float(b) / 1024), grouping) if b < 1024 * 1024 * 10: return "%sMB" % locale.format_string( "%.2f", (float(b) / (1024 * 1024)), grouping ) if b < 1024 * 1024 * 1024: return "%sMB" % locale.format_string( "%.1f", (float(b) / (1024 * 1024)), grouping ) if b < 1024 * 1024 * 1024 * 10: return "%sGB" % locale.format_string( "%.2f", (float(b) / (1024 * 1024 * 1024)), grouping ) return "%sGB" % locale.format_string( "%.1f", (float(b) / (1024 * 1024 * 1024)), grouping ) def strtime(t, func=time.localtime): """Return ISO 8601 formatted time.""" return time.strftime("%Y-%m-%d %H:%M:%S", func(t)) + strtimezone() # from quodlibet def strduration_long(duration, do_translate=True): """Turn a time value in seconds into x hours, x minutes, etc.""" if do_translate: # use global translator functions global _, _n else: # do not translate def _(x): return x def _n(a, b, n): return a if n == 1 else b if duration < 0: duration = abs(duration) prefix = "-" else: prefix = "" if duration < 1: return _("%(prefix)s%(duration).02f seconds") % { "prefix": prefix, "duration": duration, } # translation dummies _n("%d second", "%d seconds", 1) _n("%d minute", "%d minutes", 1) _n("%d hour", "%d hours", 1) _n("%d day", "%d days", 1) _n("%d year", "%d years", 1) cutoffs = [ (60, "%d second", "%d seconds"), (60, "%d minute", "%d minutes"), (24, "%d hour", "%d hours"), (365, "%d day", "%d days"), (None, "%d year", "%d years"), ] time_str = [] for divisor, single, plural in cutoffs: if duration < 1: break if divisor is None: duration, unit = 0, duration else: duration, unit = divmod(duration, divisor) if unit: time_str.append(_n(single, plural, math.ceil(unit)) % unit) time_str.reverse() if len(time_str) > 2: time_str.pop() return "{}{}".format(prefix, ", ".join(time_str)) def strtimezone(): """Return timezone info, %z on some platforms, but not supported on all. """ if time.daylight: zone = time.altzone else: zone = time.timezone return "%+04d" % (-zone // SECONDS_PER_HOUR) def stripurl(s): """Remove any lines from string after the first line. Also remove whitespace at start and end from given string.""" if not s: return s return s.splitlines()[0].strip() def limit(s, length=72): """If the length of the string exceeds the given limit, it will be cut off and three dots will be appended. @param s: the string to limit @type s: string @param length: maximum length @type length: non-negative integer @return: limited string, at most length+3 characters long """ assert length >= 0, "length limit must be a non-negative integer" if not s or len(s) <= length: return s if length == 0: return "" return "%s..." % s[:length] def strline(s): """Display string representation on one line.""" return strip_control_chars("`%s'" % s.replace("\n", "\\n")) def format_feature_warning(**kwargs): """Format warning that a module could not be imported and that it should be installed for a certain URL. """ return ( _( "Could not import %(module)s for %(feature)s." " Install %(module)s from %(url)s to use this feature." ) % kwargs ) def strip_control_chars(text): """Remove console control characters from text.""" if text: return re.sub(r"[\x01-\x1F\x7F]", "", text) return text linkchecker-10.5.0/linkcheck/threader.py000066400000000000000000000024261466565367000202100ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Support for managing threads. """ import threading class StoppableThread(threading.Thread): """Thread class with a stop() method. The thread itself has to check regularly for the stopped() condition.""" def __init__(self): """Store stop event.""" super().__init__() self._stopper = threading.Event() def stop(self): """Set stop event.""" self._stopper.set() def stopped(self, timeout=None): """Return True if stop event is set.""" return self._stopper.wait(timeout) linkchecker-10.5.0/linkcheck/trace.py000066400000000000000000000055041466565367000175100ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. import re import linecache import time import sys import threading # tracing _trace_ignore = set() _trace_filter = set() def trace_ignore(names): """Add given names to trace ignore set, or clear set if names is None.""" if names is None: _trace_ignore.clear() else: _trace_ignore.update(names) def trace_filter(patterns): """Add given patterns to trace filter set or clear set if patterns is None.""" if patterns is None: _trace_filter.clear() else: _trace_filter.update(re.compile(pat) for pat in patterns) def _trace(frame, event, arg): """Trace function calls.""" if event in ('call', 'c_call'): _trace_line(frame, event, arg) elif event in ('return', 'c_return'): _trace_line(frame, event, arg) print(" return:", arg) # elif event in ('exception', 'c_exception'): # _trace_line(frame, event, arg) return _trace def _trace_full(frame, event, arg): """Trace every executed line.""" if event == "line": _trace_line(frame, event, arg) else: _trace(frame, event, arg) return _trace_full def _trace_line(frame, event, arg): """Print current executed line.""" name = frame.f_globals["__name__"] if name in _trace_ignore: return _trace_line for pat in _trace_filter: if not pat.match(name): return _trace_line lineno = frame.f_lineno filename = frame.f_globals["__file__"] if filename.endswith((".pyc", ".pyo")): filename = filename[:-1] line = linecache.getline(filename, lineno) currentThread = threading.current_thread() tid = currentThread.ident tname = currentThread.name args = (tid, tname, time.time(), line.rstrip(), name, lineno) print("THREAD(%d) %r %.2f %s # %s:%d" % args) def trace_on(full=False): """Start tracing of the current thread (and the current thread only).""" if full: sys.settrace(_trace_full) else: sys.settrace(_trace) def trace_off(): """Stop tracing of the current thread (and the current thread only).""" sys.settrace(None) linkchecker-10.5.0/linkcheck/url.py000066400000000000000000000367131466565367000172220ustar00rootroot00000000000000# Copyright (C) 2000-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Functions for parsing and matching URL strings. """ import os import re import urllib.parse for scheme in ('ldap', 'irc'): if scheme not in urllib.parse.uses_netloc: urllib.parse.uses_netloc.append(scheme) # The character set to encode non-ASCII characters in a URL. See also # http://tools.ietf.org/html/rfc2396#section-2.1 # Note that the encoding is not really specified, but most browsers # encode in UTF-8 when no encoding is specified by the HTTP headers, # else they use the page encoding for followed link. See also # http://code.google.com/p/browsersec/wiki/Part1#Unicode_in_URLs url_encoding = "utf-8" default_ports = { 'http': 80, 'https': 443, 'ftp': 21, } # adapted from David Wheelers "Secure Programming for Linux and Unix HOWTO" # http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/\ # filter-html.html#VALIDATING-URIS _path = r"\-\_\.\!\~\*\'\(\)," _hex_safe = r"2-9a-f" _hex_full = r"0-9a-f" _part = r"([a-z0-9][-a-z0-9]{0,61}|[a-z])" _safe_char = ( fr"([a-z0-9{_path}\+]|" fr"(%[{_hex_safe}][{_hex_full}]))" ) _safe_scheme_pattern = r"(https?|ftp)" _safe_domain_pattern = fr"({_part}(\.{_part})*\.?)" _safe_host_pattern = fr"{_safe_domain_pattern}(:(80|8080|8000|443))?" _safe_path_pattern = ( fr"((/([a-z0-9{_path}]|" fr"(%[{_hex_safe}][{_hex_full}]))+)*/?)" ) _safe_fragment_pattern = fr"{_safe_char}*" _safe_cgi = fr"{_safe_char}+(=({_safe_char}|/)+)?" _safe_query_pattern = fr"({_safe_cgi}(&{_safe_cgi})*)?" _safe_param_pattern = fr"({_safe_cgi}(;{_safe_cgi})*)?" safe_url_pattern = r"{}://{}{}(#{})?".format( _safe_scheme_pattern, _safe_host_pattern, _safe_path_pattern, _safe_fragment_pattern, ) is_safe_url = re.compile(f"(?i)^{safe_url_pattern}$").match is_safe_domain = re.compile(f"(?i)^{_safe_domain_pattern}$").match # snatched form urlparse.py def splitparams(path): """Split off parameter part from path. Returns tuple (path-without-param, param) """ if '/' in path: i = path.find(';', path.rfind('/')) else: i = path.find(';') if i < 0: return path, '' return path[:i], path[i + 1:] def is_numeric_port(portstr): """return: integer port (== True) iff portstr is a valid port number, False otherwise """ if portstr.isdigit(): port = int(portstr) # 65536 == 2**16 if 0 < port < 65536: return port return False def parse_qsl(qs, encoding, keep_blank_values=0, strict_parsing=0): """Parse a query given as a string argument. @param qs: URL-encoded query string to be parsed @type qs: string @param keep_blank_values: flag indicating whether blank values in URL encoded queries should be treated as blank strings. A true value indicates that blanks should be retained as blank strings. The default false value indicates that blank values are to be ignored and treated as if they were not included. @type keep_blank_values: bool @param strict_parsing: flag indicating what to do with parsing errors. If false (the default), errors are silently ignored. If true, errors raise a ValueError exception. @type strict_parsing: bool @returns: list of triples (key, value, separator) where key and value are the split CGI parameter and separator the used separator for this CGI parameter which is either a semicolon or an ampersand @rtype: list of triples """ pairs = [] name_value_amp = qs.split('&') for name_value in name_value_amp: if ';' in name_value: pairs.extend([x, ';'] for x in name_value.split(';')) pairs[-1][1] = '&' else: pairs.append([name_value, '&']) pairs[-1][1] = '' r = [] for name_value, sep in pairs: nv = name_value.split('=', 1) if len(nv) != 2: if strict_parsing: raise ValueError("bad query field: %r" % name_value) elif len(nv) == 1: # None value indicates missing equal sign nv = (nv[0], None) else: continue if nv[1] or keep_blank_values: name = urllib.parse.unquote(nv[0].replace('+', ' '), encoding=encoding) if nv[1]: value = urllib.parse.unquote(nv[1].replace('+', ' '), encoding=encoding) else: value = nv[1] r.append((name, value, sep)) return r def idna_encode(host): """Encode hostname as internationalized domain name (IDN) according to RFC 3490. @raise: UnicodeError if hostname is not properly IDN encoded. """ if host: try: host.encode('ascii') return host, False except UnicodeError: uhost = host.encode('idna').decode('ascii') return uhost, uhost != host return host, False def split_netloc(netloc): """Separate userinfo from host in urllib.parse.SplitResult.netloc. Originated as urllib.parse._splituser(). """ userinfo, delim, hostport = netloc.rpartition('@') return (userinfo if delim else None), hostport def url_fix_host(urlparts, encoding): """Unquote and fix hostname. Returns is_idn.""" if not urlparts[1]: urlparts[2] = urllib.parse.unquote(urlparts[2], encoding=encoding) return False userpass, hostport = split_netloc(urlparts[1]) if userpass: userpass = urllib.parse.unquote(userpass, encoding=encoding) netloc, is_idn = idna_encode( urllib.parse.unquote(hostport, encoding=encoding).lower() ) # a leading backslash in path causes urlsplit() to add the # path components up to the first slash to host # try to find this case... i = netloc.find("\\") if i != -1: # ...and fix it by prepending the misplaced components to the path comps = netloc[i:] # note: still has leading backslash if not urlparts[2] or urlparts[2] == '/': urlparts[2] = comps else: urlparts[2] = "{}{}".format( comps, urllib.parse.unquote(urlparts[2], encoding=encoding), ) netloc = netloc[:i] else: # a leading ? in path causes urlsplit() to add the query to the # host name i = netloc.find("?") if i != -1: netloc, urlparts[3] = netloc.split('?', 1) # path urlparts[2] = urllib.parse.unquote(urlparts[2], encoding=encoding) if userpass: # append AT for easy concatenation userpass += "@" else: userpass = "" if urlparts[0] in default_ports: dport = default_ports[urlparts[0]] host, port = splitport(netloc, port=dport) if host.endswith("."): host = host[:-1] if port != dport: host = f"{host}:{port}" netloc = host urlparts[1] = userpass + netloc return is_idn def url_fix_mailto_urlsplit(urlparts): """Split query part of mailto url if found.""" sep = "?" if sep in urlparts[2]: urlparts[2], urlparts[3] = urlparts[2].split(sep, 1) # wayback urls include in the path http[s]://. By default the # tidying mechanism in linkchecker encodes the : and deletes the second slash # This function reverses these corrections. This function expects only the # path section of the URL as input. wayback_regex = re.compile(r'(https?)(\%3A/|:/)') def url_fix_wayback_query(path): return wayback_regex.sub(r'\1://', path) def url_parse_query(query, encoding): """Parse and re-join the given CGI query.""" # if ? is in the query, split it off, seen at msdn.microsoft.com append = "" while '?' in query: query, rest = query.rsplit('?', 1) append = '?' + url_parse_query(rest, encoding=encoding) + append f = [] for k, v, sep in parse_qsl(query, keep_blank_values=True, encoding=encoding): k = urllib.parse.quote(k, safe='/-:,;') if v: v = urllib.parse.quote(v, safe='/-:,;') f.append(f"{k}={v}{sep}") elif v is None: f.append(f"{k}{sep}") else: # some sites do not work when the equal sign is missing f.append(f"{k}={sep}") return ''.join(f) + append def urlunsplit(urlparts): """Same as urllib.parse.urlunsplit but with extra UNC path handling for Windows OS.""" res = urllib.parse.urlunsplit(urlparts) if os.name == 'nt' and urlparts[0] == 'file' and '|' not in urlparts[2]: # UNC paths must have 4 slashes: 'file:////server/path' # Depending on the path in urlparts[2], urllib.parse.urlunsplit() # left only two or three slashes. This is fixed below repl = 'file://' if urlparts[2].startswith('//') else 'file:/' res = res.replace('file:', repl) return res def url_norm(url, encoding): """Normalize the given URL which must be quoted. Supports unicode hostnames (IDNA encoding) according to RFC 3490. @return: (normed url, idna flag) @rtype: tuple of length two """ urlparts = list(urllib.parse.urlsplit(url)) # scheme urlparts[0] = urllib.parse.unquote(urlparts[0], encoding=encoding).lower() # mailto: urlsplit is broken if urlparts[0] == 'mailto': url_fix_mailto_urlsplit(urlparts) # host (with path or query side effects) is_idn = url_fix_host(urlparts, encoding) # query urlparts[3] = url_parse_query(urlparts[3], encoding=encoding) if urlparts[0] in urllib.parse.uses_relative: # URL has a hierarchical path we should norm if not urlparts[2]: # Empty path is allowed if both query and fragment are also empty. # Note that in relative links, urlparts[0] might be empty. # In this case, do not make any assumptions. if urlparts[0] and (urlparts[3] or urlparts[4]): urlparts[2] = '/' else: # fix redundant path parts urlparts[2] = collapse_segments(urlparts[2]) # anchor urlparts[4] = urllib.parse.unquote(urlparts[4], encoding=encoding) # quote parts again urlparts[0] = urllib.parse.quote(urlparts[0]) # scheme urlparts[1] = urllib.parse.quote(urlparts[1], safe='@:') # host urlparts[2] = urllib.parse.quote(urlparts[2], safe=_nopathquote_chars) # path if not urlparts[0].startswith("feed"): # unencode colon in http[s]:// in wayback path urlparts[2] = url_fix_wayback_query(urlparts[2]) urlparts[4] = urllib.parse.quote(urlparts[4], safe="!$&'()*+,-./;=?@_~") # anchor res = urlunsplit(urlparts) if url.endswith('#') and not urlparts[4]: # re-append trailing empty fragment res += '#' return (res, is_idn) _slashes_ro = re.compile(r"/+") _thisdir_ro = re.compile(r"^\./") _samedir_ro = re.compile(r"/\./|/\.$") _parentdir_ro = re.compile(r"^/(\.\./)+|/(?!\.\./)[^/]+/\.\.(/|$)") _relparentdir_ro = re.compile(r"^(?!\.\./)[^/]+/\.\.(/|$)") def collapse_segments(path): """Remove all redundant segments from the given URL path. Precondition: path is an unquoted url path""" # replace backslashes # note: this is _against_ the specification (which would require # backslashes to be left alone, and finally quoted with '%5C') # But replacing has several positive effects: # - Prevents path attacks on Windows systems (using \.. parent refs) # - Fixes bad URLs where users used backslashes instead of slashes. # This is a far more probable case than users having an intentional # backslash in the path name. path = path.replace('\\', '/') # shrink multiple slashes to one slash path = _slashes_ro.sub("/", path) # collapse redundant path segments path = _thisdir_ro.sub("", path) path = _samedir_ro.sub("/", path) # collapse parent path segments # note: here we exploit the fact that the replacements happen # to be from left to right (see also _parentdir_ro above) newpath = _parentdir_ro.sub("/", path) while newpath != path: path = newpath newpath = _parentdir_ro.sub("/", path) # collapse parent path segments of relative paths # (ie. without leading slash) newpath = _relparentdir_ro.sub("", path) while newpath != path: path = newpath newpath = _relparentdir_ro.sub("", path) return path url_is_absolute = re.compile(r"^[-\.a-z]+:", re.I).match def url_quote(url, encoding): """Quote given URL.""" if not url_is_absolute(url): return document_quote(url) urlparts = list(urllib.parse.urlsplit(url)) urlparts[0] = urllib.parse.quote(urlparts[0]) # scheme urlparts[1] = urllib.parse.quote(urlparts[1], safe=':') # host urlparts[2] = urllib.parse.quote(urlparts[2], safe='/=,') # path urlparts[3] = urllib.parse.quote(urlparts[3], safe='&=,') # query f = [] for k, v, sep in parse_qsl( urlparts[3], encoding=encoding, keep_blank_values=True ): # query k = urllib.parse.quote(k, safe='/-:,;') if v: v = urllib.parse.quote(v, safe='/-:,;') f.append(f"{k}={v}{sep}") else: f.append(f"{k}{sep}") urlparts[3] = ''.join(f) urlparts[4] = urllib.parse.quote(urlparts[4]) # anchor return urlunsplit(urlparts) def document_quote(document): """Quote given document.""" doc, delim, query = document.rpartition('?') if not delim: doc = document query = None doc = urllib.parse.quote(doc, safe='/=,') if query: return f"{doc}?{query}" return doc _nopathquote_chars = "-;/=,~*+()@!" if os.name == 'nt': _nopathquote_chars += "|" _safe_url_chars = re.escape(_nopathquote_chars + "_:.&#%?[]!") + "a-zA-Z0-9" _safe_url_chars_ro = re.compile(fr"^[{_safe_url_chars}]*$") def url_needs_quoting(url): """Check if url needs percent quoting. Note that the method does only check basic character sets, and not any other syntax. The URL might still be syntactically incorrect even when it is properly quoted. """ if url.rstrip() != url: # handle trailing whitespace as a special case # since '$' matches immediately before a end-of-line return True return not _safe_url_chars_ro.match(url) def splitport(host, port=0): """Split optional port number from host. If host has no port number, the given default port is returned. @param host: host name @type host: string @param port: the port number (default 0) @type port: int @return: tuple of (host, port) @rtype: tuple of (string, int) """ if ":" in host: shost, sport = host.split(":", 1) iport = is_numeric_port(sport) if iport: host, port = shost, iport elif not sport: # empty port, ie. the host was "hostname:" host = shost else: # For an invalid non-empty port leave the host name as is pass return host, port linkchecker-10.5.0/po/000077500000000000000000000000001466565367000145175ustar00rootroot00000000000000linkchecker-10.5.0/po/Makefile000066400000000000000000000015401466565367000161570ustar00rootroot00000000000000XGETTEXT := xgettext MSGFMT := msgfmt MSGMERGE := msgmerge POSOURCES = $(shell find ../linkcheck -name \*.py) \ $(shell python3 -c 'import argparse; print(argparse.__file__)') PACKAGE = linkchecker TEMPLATE = $(PACKAGE).pot MYMAIL := bastian.kleineidam@web.de BUGSURL = https://github.com/linkchecker/linkchecker POFILES = $(wildcard *.po) all: $(POFILES) %.po: $(TEMPLATE) $(MSGMERGE) -U --suffix=.bak $@ $< template: $(TEMPLATE) $(TEMPLATE): $(POSOURCES) $(XGETTEXT) -w 80 --default-domain=$(PACKAGE) --language=Python \ --copyright-holder="Bastian Kleineidam <$(MYMAIL)>" \ --package-name=LinkChecker \ --from-code=UTF-8 \ --msgid-bugs-address=$(BUGSURL) -o $(TEMPLATE) \ --keyword=_n:1,2 $(POSOURCES) check: @for po in $(POFILES); do \ $(MSGFMT) -cv --statistics -o - $$po >/dev/null; \ done clean: rm -f *.bak .PHONY: check clean linkchecker-10.5.0/po/de.po000066400000000000000000002035521466565367000154560ustar00rootroot00000000000000# German translation for LinkChecker. # Bastian Kleineidam , 2009-2022. # msgid "" msgstr "" "Project-Id-Version: LinkChecker\n" "Report-Msgid-Bugs-To: https://github.com/linkchecker/linkchecker\n" "POT-Creation-Date: 2024-08-27 18:47+0000\n" "PO-Revision-Date: 2022-11-01 19:25+0000\n" "Last-Translator: Bastian Kleineidam \n" "Language-Team: de \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 40.0\n" #: ../linkcheck/director/__init__.py:36 #, fuzzy, python-format msgid "Problem using login URL: %(msg)s." msgstr "Fehler bei Login URL: %(msg)s." #: ../linkcheck/director/__init__.py:39 #, python-format msgid "Error using login URL: %(msg)s." msgstr "Fehler bei Login URL: %(msg)s." #: ../linkcheck/director/__init__.py:44 #, fuzzy, python-format msgid "Error starting log output: %(msg)s." msgstr "Fehler bei Login URL: %(msg)s." #: ../linkcheck/director/__init__.py:60 msgid "" "Could not start a new thread. Check that the current user is allowed to " "start new threads." msgstr "" "Konnte keinen neuen Thread starten. Überprüfen sie, ob der aktuelle Benutzer " "neue Threads starten darf." #: ../linkcheck/director/__init__.py:93 #, fuzzy msgid "interrupt; waiting for active threads to finish" msgstr "Benutzerabbruch; warte auf Beendigung von aktiven Verbindungen" #: ../linkcheck/director/__init__.py:94 msgid "another interrupt will exit immediately" msgstr "ein weiter Abbruch beendet dieses Programm sofort" #: ../linkcheck/director/__init__.py:110 msgid "user abort; force shutdown" msgstr "Benutzerabbruch; erzwinge Programmende" #: ../linkcheck/director/aggregator.py:54 #, fuzzy, python-format msgid "Could not parse cookie file: %s. %s" msgstr "Konnte Cookie-Datei nicht parsen: %s" #: ../linkcheck/director/aggregator.py:188 msgid "These URLs are still active:" msgstr "Folgende URLs sind noch aktiv:" #: ../linkcheck/director/aggregator.py:200 #, python-format msgid "" "%(num)d URLs are still active. After a timeout of %(timeout)s the active " "URLs will stop." msgstr "" #: ../linkcheck/director/console.py:38 #, fuzzy, python-format msgid "%2d thread active" msgid_plural "%2d threads active" msgstr[0] "%2d URL aktiv" msgstr[1] "%2d URLs aktiv" #: ../linkcheck/director/console.py:40 #, fuzzy, python-format msgid "%5d link queued" msgid_plural "%5d links queued" msgstr[0] "%5d URL zu prüfen" msgstr[1] "%5d URLs zu prüfen" #: ../linkcheck/director/console.py:42 #, python-format msgid "%4d link" msgid_plural "%4d links" msgstr[0] "%4d Verknüpfung" msgstr[1] "%4d Verknüpfungen" #: ../linkcheck/director/console.py:44 #, python-format msgid "%3d URL" msgid_plural "%3d URLs" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:46 #, python-format msgid "runtime %s" msgstr "Laufzeit %s" #: ../linkcheck/director/console.py:66 #, python-format msgid "" "********** Oops, I did it again. *************\n" "\n" "You have found an internal error in LinkChecker. Please write a bug report\n" "at %s\n" "and include the following information:\n" "- the URL or file you are testing\n" "- the system information below\n" "\n" "When using the commandline client:\n" "- your commandline arguments and any custom configuration files.\n" "- the output of a debug run with option \"-Dall\"\n" "\n" "Not disclosing some of the information above due to privacy reasons is ok.\n" "I will try to help you nonetheless, but you have to give me something\n" "I can work with ;) .\n" msgstr "" "********** Hoppla. *************\n" "\n" "Sie haben einen internen Fehler in LinkChecker entdeckt. Bitte schreiben " "Sie\n" "einen Fehlerbericht an %s\n" "mit den folgenden Informationen:\n" "- die URL oder Datei, welche Sie gerade prüfen\n" "- die untenstehenden Systeminformationen.\n" "\n" "Bei Benutzung des Kommandozeilenprogramms:\n" "- ihre Kommandozeilenargumente und/oder Ihre Konfiguration.\n" "- die Ausgabe eines Debuglaufs mit Option \"-Dall\"\n" "\n" "Wenn Sie Informationen aus privaten Gründen unterlassen, ist das in " "Ordnung.\n" "Ich werde trotzdem versuchen, Ihnen zu helfen. Sie müssen mir allerdings\n" "irgendwas geben, womit ich arbeiten kann ;).\n" #: ../linkcheck/director/console.py:94 msgid "******** LinkChecker internal error, over and out ********" msgstr "******** LinkChecker interner Fehler, und tschüß ********" #: ../linkcheck/director/console.py:140 msgid "System info:" msgstr "Systeminformation:" #: ../linkcheck/director/console.py:142 msgid "Released on:" msgstr "" #: ../linkcheck/director/console.py:144 ../linkcheck/command/linkchecker.py:130 #, python-format msgid "Python %(version)s on %(platform)s" msgstr "Python %(version)s auf %(platform)s" #: ../linkcheck/director/console.py:152 msgid "Local time:" msgstr "Uhrzeit:" #: ../linkcheck/director/console.py:153 msgid "sys.argv:" msgstr "" #: ../linkcheck/director/console.py:158 msgid "released" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:56 #, fuzzy msgid "HTML syntax check plugin is broken. Fixes welcome." msgstr "tidy HTML Parser verursachte Fehler: %(msg)s" #: ../linkcheck/plugins/syntaxchecks.py:74 msgid "valid HTML syntax" msgstr "gültige HTML Syntax" #: ../linkcheck/plugins/syntaxchecks.py:81 #, fuzzy, python-format msgid "HTML syntax check plugin error: %(msg)s " msgstr "tidy HTML Parser verursachte Fehler: %(msg)s" #: ../linkcheck/plugins/syntaxchecks.py:114 msgid "valid CSS syntax" msgstr "gültige CSS Syntax" #: ../linkcheck/plugins/syntaxchecks.py:121 #, fuzzy, python-format msgid "CSS syntax check plugin error: %(msg)s " msgstr "Syntaxfehler in %(arg)r: %(msg)s" #: ../linkcheck/plugins/syntaxchecks.py:132 #, python-format msgid "%(w3type)s validation error at line %(line)s col %(column)s: %(msg)s" msgstr "" "%(w3type)s Validierungsfehler in Zeile %(line)s Spalte %(column)s: %(msg)s" #: ../linkcheck/plugins/syntaxchecks.py:136 #, python-format msgid "%(w3type)s validation error at line %(line)s: %(msg)s" msgstr "%(w3type)s Validierungsfehler in Zeile %(line)s: %(msg)s" #: ../linkcheck/plugins/markdowncheck.py:88 #: ../linkcheck/plugins/regexcheck.py:45 #, fuzzy, python-format msgid "Invalid regex pattern %r: %s" msgstr "ungültiger leerer Wert für %s: %s\n" #: ../linkcheck/plugins/regexcheck.py:61 #, python-format msgid "Found %(match)r at line %(line)d in link contents." msgstr "Habe %(match)r in Zeile %(line)d im Inhalt der Verknüpfung gefunden." #: ../linkcheck/plugins/sslcertcheck.py:70 msgid "certificate did not include \"notAfter\" information" msgstr "Zertifikat besitzt keine \"notAfter\"-Information" #: ../linkcheck/plugins/sslcertcheck.py:73 msgid "SSL verification is disabled; enable the sslverify option" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:85 #, fuzzy, python-format msgid "Invalid SSL certificate \"notAfter\" value %r" msgstr "ungültiger \"notAfter\" Zertifikatwert %r" #: ../linkcheck/plugins/sslcertcheck.py:94 #, python-format msgid "SSL certificate is expired on %(expire)s." msgstr "Zertifikat ist am %(expire)s abgelaufen" #: ../linkcheck/plugins/sslcertcheck.py:100 #, python-format msgid "SSL certificate expires on %(expire)s and is only %(valid)s valid." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:104 #, python-format msgid "SSL certificate expires on %(expire)s and is %(valid)s valid." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:118 #: ../linkcheck/configuration/confparse.py:98 #: ../linkcheck/configuration/confparse.py:116 #, python-format msgid "invalid value for %s: %d must not be less than %d" msgstr "ungültiger Wert für %s: %d darf nicht kleiner als %d sein" #: ../linkcheck/plugins/locationinfo.py:46 #, python-format msgid "URL is located in %(location)s." msgstr "URL befindet sich in %(location)s." #: ../linkcheck/plugins/viruscheck.py:101 msgid "clamd is not ready for stream scanning" msgstr "clamd ist nicht bereit, einen Stream zu prüfen" #: ../linkcheck/plugins/viruscheck.py:160 msgid "ScannerDaemonOutputFormat must be disabled" msgstr "ScannerDaemonOutputFormat muss deaktiviert sein" #: ../linkcheck/plugins/viruscheck.py:163 msgid "only one of TCPSocket and LocalSocket must be enabled" msgstr "nur einer von TCPSocket oder LocalSocket muss aktiviert sein" #: ../linkcheck/plugins/viruscheck.py:193 msgid "one of TCPSocket or LocalSocket must be enabled" msgstr "einer von TCPSocket oder LocalSocket muss aktiviert sein" #: ../linkcheck/plugins/viruscheck.py:229 msgid "Could not connect to ClamAV daemon." msgstr "Konnte nicht zu ClamAV verbinden." #: ../linkcheck/plugins/anchorcheck.py:70 #, fuzzy, python-format msgid "Anchor `%(name)s' (decoded: `%(decoded)s') not found." msgstr "Anker `%(name)s' nicht gefunden." #: ../linkcheck/plugins/anchorcheck.py:71 #, python-format msgid "Available anchors: %(anchors)s." msgstr "Verfügbare Anker: %(anchors)s." #: ../linkcheck/cookies.py:46 #, fuzzy msgid "No entries found" msgstr "Es wurde kein NNTP Server gefunden." #: ../linkcheck/cmdline.py:61 #, python-format msgid "Error: %(msg)s" msgstr "Fehler: %(msg)s" #: ../linkcheck/cmdline.py:63 #, python-format msgid "Execute '%(program)s -h' for help" msgstr "Führen Sie '%(program)s -h' aus, um Hilfe zu erhalten" #: ../linkcheck/configuration/__init__.py:227 #, python-format msgid "Configuration file %r does not exist." msgstr "Konfigurationsdatei %r existiert nicht." #: ../linkcheck/configuration/__init__.py:229 #, python-format msgid "Configuration file %r is not readable." msgstr "Konfigurationsdatei %r ist nicht lesbar." #: ../linkcheck/configuration/__init__.py:239 msgid "missing user or URL pattern in authentication data." msgstr "" "Fehlender Benutzer oder regulärer URL Ausdruck in Authentifizierungsdaten." #: ../linkcheck/configuration/__init__.py:274 msgid "activating text logger output." msgstr "aktiviere Loggerausgabe text." #: ../linkcheck/configuration/__init__.py:285 msgid "no user/password authentication data found for login URL." msgstr "keine Benutzer/Passwort-Authentifizierung für Login URL gefunden." #: ../linkcheck/configuration/__init__.py:289 msgid "login URL is not a HTTP URL." msgstr "Login URL ist keine HTTP URL." #: ../linkcheck/configuration/__init__.py:293 msgid "login URL is incomplete." msgstr "Login URL ist unvollständig." #: ../linkcheck/configuration/__init__.py:296 #, python-format msgid "disabling login URL %(url)s." msgstr "deaktiviere Login URL %(url)s." #: ../linkcheck/configuration/__init__.py:349 #, fuzzy, python-format msgid "could not create plugin directory %(dirname)r: %(errmsg)r" msgstr "Konnte Projekt %(filename)s nicht laden: %(err)s" #: ../linkcheck/configuration/__init__.py:397 #, python-format msgid "" "could not copy initial configuration file %(src)r to %(dst)r: %(errmsg)r" msgstr "" "Konnte initiale Konfigurationsdatei %(src)r nicht nach %(dst)r kopieren: " "%(errmsg)r" #: ../linkcheck/configuration/confparse.py:62 #, fuzzy, python-format msgid "configuration files %s contain no sections." msgstr "Konfigurationsdatei %r existiert nicht." #: ../linkcheck/configuration/confparse.py:75 #, python-format msgid "Error parsing configuration: %s" msgstr "Fehler beim Parsen der Konfiguration: %s" #: ../linkcheck/configuration/confparse.py:83 #, python-format msgid "invalid empty value for %s: %s\n" msgstr "ungültiger leerer Wert für %s: %s\n" #: ../linkcheck/configuration/confparse.py:103 #: ../linkcheck/configuration/confparse.py:121 #, python-format msgid "invalid value for %s: %d must not be greater than %d" msgstr "ungültiger Wert für %s: %d darf nicht größer als %d sein" #: ../linkcheck/configuration/confparse.py:136 msgid "" "The blacklist section in linkcheckerrc is deprecated, please rename to " "failures" msgstr "" #: ../linkcheck/configuration/confparse.py:237 #, python-format msgid "missing auth part in entry %(val)r" msgstr "fehlende Authentifizierung in entry %(val)r" #: ../linkcheck/configuration/confparse.py:247 #, python-format msgid "invalid login URL `%s'. Only HTTP and HTTPS URLs are supported." msgstr "ungültige Login URL `%s'. Nur HTTP und HTTPS URLs sind unterstützt." #: ../linkcheck/configuration/confparse.py:276 #, python-format msgid "" "The configuration file %s contains password information (in section [%s] and " "options %s) and the file is readable by others. Please make the file only " "readable by you." msgstr "" #: ../linkcheck/configuration/confparse.py:285 #, python-format msgid "For example execute 'chmod go-rw %s'." msgstr "Führen Sie zum Beispiel 'chmod go-rw %s' aus." #: ../linkcheck/configuration/confparse.py:290 #, python-format msgid "See %(url)s for more info on setting file permissions." msgstr "" "Siehe %(url)s für mehr Informationen über das Setzen von Dateiberechtigungen." #: ../linkcheck/lc_cgi.py:215 #, fuzzy, python-format msgid "could not set locale %r: %s" msgstr "konnte Inhalt nicht lesen: %(msg)s" #: ../linkcheck/lc_cgi.py:217 #, python-format msgid "unsupported language %r" msgstr "nicht unterstützte Sprache %r" #: ../linkcheck/lc_cgi.py:222 msgid "empty url was given" msgstr "leere URL wurde angegeben" #: ../linkcheck/lc_cgi.py:224 #, python-format msgid "disallowed url %r was given" msgstr "ungültige URL %r wurde angegeben" #: ../linkcheck/lc_cgi.py:226 msgid "no url was given" msgstr "keine URL wurde angegeben" #: ../linkcheck/lc_cgi.py:231 #, python-format msgid "invalid recursion level %r" msgstr "ungültiger Rekursionslevel %r" #: ../linkcheck/lc_cgi.py:237 #, python-format msgid "invalid %s option %r" msgstr "ungültige %s Option %r" #: ../linkcheck/lc_cgi.py:264 #, python-format msgid "" "\n" "\n" "\n" "LinkChecker Online Error\n" "\n" "
\n" "Error: %s
\n" "The LinkChecker Online script has encountered an error. Please ensure\n" "that your provided URL link begins with http:// and\n" "contains only these characters: A-Za-z0-9./_~-

\n" "Errors are logged.\n" "
\n" "\n" "" msgstr "" "\n" "\n" "\n" "LinkChecker Online Fehler\n" "
Fehler: %s
Das LinkChecker Online Skript ist\n" "auf einen Fehler gestoßen. Bitte stellen Sie sicher, daß die\n" "angegebene URL mit http:// beginnt und nur diese Zeichen\n" "enthält: A-Za-z0-9./_~-

Fehler werden geloggt.\n" "
" #: ../linkcheck/checker/fileurl.py:142 #, python-format msgid "Could not get current working directory: %(msg)s" msgstr "Konnte aktuelles Arbeitsverzeichnis nicht ermitteln: %(msg)s" #: ../linkcheck/checker/fileurl.py:175 ../linkcheck/checker/fileurl.py:339 msgid "Added trailing slash to directory." msgstr "Schrägstrich wurde zu Verzeichnis hinzugefügt." #: ../linkcheck/checker/fileurl.py:198 ../linkcheck/checker/fileurl.py:352 msgid "" "local files are only checked without parent URL or when the parent URL is " "also a file" msgstr "" "lokale Dateien werden nur ohne Eltern-URL geprüft oder wenn die Eltern-URL " "auch eine Datei ist" #: ../linkcheck/checker/fileurl.py:203 ../linkcheck/checker/fileurl.py:367 msgid "directory" msgstr "Verzeichnis" #: ../linkcheck/checker/fileurl.py:222 #, python-format msgid "" "The URL path %(path)r is not the same as the system path %(realpath)r. You " "should always use the system path in URLs." msgstr "" "Der URL Pfad %(path)r ist nicht derselbe wie der Systempfad %(realpath)r. " "Sie sollten immer den Systempfad in URLs benutzen." #: ../linkcheck/checker/fileurl.py:360 #, python-format msgid "" "URL `%s' is a directory with an anchor. When checking local files " "AnchorCheck does not support anchors for directories." msgstr "" #: ../linkcheck/checker/itmsservicesurl.py:31 msgid "Missing required url parameter" msgstr "" #: ../linkcheck/checker/urlbase.py:79 #, python-format msgid "URL has unparsable domain name: %(name)s" msgstr "URL besitzt einen nicht analysierbaren Rechnernamen: %(name)s" #: ../linkcheck/checker/urlbase.py:163 #, fuzzy msgid "The URL is outside of the domain filter, checked only syntax." msgstr "" "Die Weiterleitungs-URL ist außerhalb des Domain Filters; prüfe lediglich " "Syntax." #: ../linkcheck/checker/urlbase.py:166 msgid "filtered" msgstr "gefiltert" #: ../linkcheck/checker/urlbase.py:216 #, python-format msgid "Leading or trailing whitespace in URL `%(url)s'." msgstr "Die URL %(url)s enthält Leerzeichen am Anfang oder Ende." #: ../linkcheck/checker/urlbase.py:340 #, fuzzy, python-format msgid "The URL with content type %r is not parseable." msgstr "Der URL Inhalt ist zu groß." #: ../linkcheck/checker/urlbase.py:445 msgid "URL is empty" msgstr "URL ist leer" #: ../linkcheck/checker/urlbase.py:460 #, python-format msgid "Effective URL %(url)r." msgstr "Effektive URL %(url)r." #: ../linkcheck/checker/urlbase.py:467 #, python-format msgid "URL length %(len)d is longer than %(max)d." msgstr "URL-Länge %(len)d ist länger als %(max)d." #: ../linkcheck/checker/urlbase.py:517 ../linkcheck/checker/urlbase.py:523 #, python-format msgid "URL host %(host)r has invalid port" msgstr "URL Rechner %(host)r hat eine ungültige Portnummer" #: ../linkcheck/checker/urlbase.py:530 msgid "URL has empty hostname" msgstr "URL hat leeren Rechnernamen" #: ../linkcheck/checker/urlbase.py:555 #, python-format msgid "URL %(url)s has obfuscated IP address %(ip)s" msgstr "URL %(url)s besitzt die verschleierte IP-Adresse %(ip)s" #: ../linkcheck/checker/urlbase.py:591 msgid "Hostname not found" msgstr "Rechnername nicht gefunden" #: ../linkcheck/checker/urlbase.py:594 #, fuzzy, python-format msgid "Bad hostname %(host)r: %(msg)s" msgstr "konnte Rechnernamen %(host)r nicht parsen: %(msg)s" #: ../linkcheck/checker/urlbase.py:614 #, python-format msgid "could not get content: %(msg)s" msgstr "konnte Inhalt nicht lesen: %(msg)s" #: ../linkcheck/checker/urlbase.py:669 #, python-format msgid "Content size %(size)s is larger than %(maxbytes)s." msgstr "Inhalt %(size)s is größer als %(maxbytes)s." #: ../linkcheck/checker/urlbase.py:763 msgid "Content size is zero." msgstr "Größe des Inhalts ist Null." #: ../linkcheck/checker/urlbase.py:800 ../linkcheck/checker/httpurl.py:348 msgid "File size too large" msgstr "Dateigröße ist zu groß" #: ../linkcheck/checker/urlbase.py:881 #, python-format msgid "URL has unparsable domain name: %(domain)s" msgstr "URL besitzt einen nicht analysierbaren Rechnernamen: %(domain)s" #: ../linkcheck/checker/unknownurl.py:32 #, python-format msgid "%(scheme)s URL ignored." msgstr "%(scheme)s URL ignoriert." #: ../linkcheck/checker/unknownurl.py:34 msgid "ignored" msgstr "ignoriert" #: ../linkcheck/checker/unknownurl.py:36 msgid "URL is unrecognized or has invalid syntax" msgstr "URL ist unbekannt oder besitzt ungültige Syntax" #: ../linkcheck/checker/mailtourl.py:88 #, fuzzy, python-format msgid "No mail addresses or email subject found in `%(url)s'." msgstr "Keine Adressen wurden in `%(url)s' gefunden." #: ../linkcheck/checker/mailtourl.py:132 #, python-format msgid "Error parsing CGI values: %s" msgstr "Fehler beim Parsen der CGI-Werte: %s" #: ../linkcheck/checker/mailtourl.py:158 #, python-format msgid "" "Mail address `%(addr)s' too long. Allowed 256 chars, was %(length)d chars." msgstr "" "E-Mail-Adresse `%(addr)s' ist zu lang. Erlaubt sind 256 Zeichen, es waren " "aber %(length)d Zeichen." #: ../linkcheck/checker/mailtourl.py:168 #, python-format msgid "Missing `@' in mail address `%(addr)s'." msgstr "Fehlendes `@' in E-Mail-Adresse `%(addr)s'." #: ../linkcheck/checker/mailtourl.py:177 #, python-format msgid "Missing local part of mail address `%(addr)s'." msgstr "Fehlender lokaler Teil der E-Mail-Adresse `%(addr)s'." #: ../linkcheck/checker/mailtourl.py:184 #, python-format msgid "Missing domain part of mail address `%(addr)s'." msgstr "Fehlender Domänen-Teil der E-Mail-Adresse `%(addr)s'." #: ../linkcheck/checker/mailtourl.py:192 #, python-format msgid "" "Local part of mail address `%(addr)s' too long. Allowed 64 chars, was " "%(length)d chars." msgstr "" "Lokaler Teil der E-Mail-Adresse `%(addr)s' ist zu lang. Erlaubt sind 64 " "Zeichen, es waren aber %(length)d Zeichen." #: ../linkcheck/checker/mailtourl.py:203 #, python-format msgid "" "Domain part of mail address `%(addr)s' too long. Allowed 255 chars, was " "%(length)d chars." msgstr "" "Domänen-Teil der E-Mail-Adresse `%(addr)s' ist zu lang. Erlaubt sind 255 " "Zeichen, es waren aber %(length)d Zeichen." #: ../linkcheck/checker/mailtourl.py:218 #, python-format msgid "Unquoted double quote or backslash in mail address `%(addr)s'." msgstr "" "Nicht kodiertes doppeltes Anführungszeichen oder Escape in E-Mail-Adresse " "`%(addr)s'." #: ../linkcheck/checker/mailtourl.py:227 #, python-format msgid "Local part of mail address `%(addr)s' may not start with a dot." msgstr "" "Der lokale Teil der E-Mail-Adresse `%(addr)s' darf nicht mit einem Punkt " "beginnen." #: ../linkcheck/checker/mailtourl.py:235 #, python-format msgid "Local part of mail address `%(addr)s' may not end with a dot." msgstr "" "Der lokale Teil der E-Mail-Adresse `%(addr)s' darf nicht mit einem Punkt " "enden." #: ../linkcheck/checker/mailtourl.py:243 #, python-format msgid "Local part of mail address `%(addr)s' may not contain two dots." msgstr "" "Der lokale Teil der E-Mail-Adresse `%(addr)s' darf nicht zwei Punkte " "beinhalten." #: ../linkcheck/checker/mailtourl.py:253 #, python-format msgid "" "Local part of mail address `%(addr)s' contains unquoted character `%(char)s." msgstr "" "Lokaler Teil der E-Mail-Adresse `%(addr)s' beinhaltet ein nicht kodiertes " "Zeichen `%(char)s." #: ../linkcheck/checker/mailtourl.py:271 #, python-format msgid "Domain part of mail address `%(addr)s' has invalid IP." msgstr "" "Domänen-Teil der E-Mail-Adresse `%(addr)s' besitzt eine ungültige IP-Adresse." #: ../linkcheck/checker/mailtourl.py:281 #, python-format msgid "Invalid domain part of mail address `%(addr)s'." msgstr "Ungültige Domänen-Teil der E-Mail-Adresse `%(addr)s'." #: ../linkcheck/checker/mailtourl.py:289 #, python-format msgid "Invalid top level domain part of mail address `%(addr)s'." msgstr "Ungültige Toplevel-Domänen-Teil der E-Mail-Adresse `%(addr)s'." #: ../linkcheck/checker/mailtourl.py:327 #, python-format msgid "No MX mail host for %(domain)s found." msgstr "Kein MX mail host für %(domain)s gefunden." #: ../linkcheck/checker/mailtourl.py:336 #, python-format msgid "No host for %(domain)s found." msgstr "Kein Rechner für %(domain)s gefunden." #: ../linkcheck/checker/mailtourl.py:353 #, python-format msgid "Got invalid DNS answer %(answer)s for %(domain)s." msgstr "Ungültige DNS Antwort %(answer)s für %(domain)s erhalten." #: ../linkcheck/checker/mailtourl.py:366 #, fuzzy msgid "Valid mail address syntax" msgstr "Ungültige Mail Syntax" #: ../linkcheck/checker/const.py:99 msgid "The effective URL is different from the original." msgstr "Die effektive URL unterscheidet sich vom Original." #: ../linkcheck/checker/const.py:100 msgid "Could not get the content of the URL." msgstr "Konnte den Inhalt der URL nicht bekommen." #: ../linkcheck/checker/const.py:101 msgid "The URL content size is too large." msgstr "Der URL Inhalt ist zu groß." #: ../linkcheck/checker/const.py:102 msgid "The URL content size is zero." msgstr "Der URL Inhaltsgrößenangabe ist Null." #: ../linkcheck/checker/const.py:103 #, fuzzy msgid "The URL content type is not parseable." msgstr "Der URL Inhalt ist zu groß." #: ../linkcheck/checker/const.py:104 msgid "The URL is longer than the recommended size." msgstr "Die URL ist länger als die empfohlene Länge." #: ../linkcheck/checker/const.py:105 msgid "The URL contains leading or trailing whitespace." msgstr "Die URL %(url)s enthält Leerzeichen am Anfang oder Ende." #: ../linkcheck/checker/const.py:106 msgid "The file: URL is missing a trailing slash." msgstr "Der file: URL fehlt ein abschließender Schrägstrich." #: ../linkcheck/checker/const.py:108 msgid "The file: path is not the same as the system specific path." msgstr "Der file: Pfad ist nicht derselbe wie der Systempfad." #: ../linkcheck/checker/const.py:111 msgid "A local directory with an anchor, not supported by AnchorCheck." msgstr "" #: ../linkcheck/checker/const.py:112 msgid "The ftp: URL is missing a trailing slash." msgstr "Der ftp: URL fehlt ein abschließender Schrägstrich." #: ../linkcheck/checker/const.py:113 msgid "The URL had no content." msgstr "Die URL besitzt keinen Inhalt." #: ../linkcheck/checker/const.py:114 msgid "An error occurred while storing a cookie." msgstr "Ein Fehler trat auf während des Speicherns eines Cookies." #: ../linkcheck/checker/const.py:115 msgid "The URL request was rate limited." msgstr "" #: ../linkcheck/checker/const.py:116 msgid "Redirected to a different URL." msgstr "" #: ../linkcheck/checker/const.py:117 msgid "The mail MX host could not be found." msgstr "Der MX Mail-Rechner konnte nicht gefunden werden." #: ../linkcheck/checker/const.py:118 msgid "The IP is obfuscated." msgstr "Die IP-Adresse ist verschleiert." #: ../linkcheck/checker/const.py:119 #, fuzzy msgid "XML could not be parsed." msgstr "Der MX Mail-Rechner konnte nicht gefunden werden." #: ../linkcheck/checker/ftpurl.py:75 msgid "Got no answer from FTP server" msgstr "Keine Antwort vom FTP Server" #: ../linkcheck/checker/ftpurl.py:78 #, python-format msgid "Remote host has closed connection: %(msg)s" msgstr "Entfernter Rechner hat die Verbindung geschlossen: %(msg)s" #: ../linkcheck/checker/ftpurl.py:124 msgid "Missing trailing directory slash in ftp url." msgstr "Fehlender / am Ende der FTP url." #: ../linkcheck/checker/ftpurl.py:188 msgid "FTP file size too large" msgstr "FTP Dateigröße ist zu groß" #: ../linkcheck/checker/httpurl.py:138 #, fuzzy msgid "Access denied by robots.txt, checked only syntax." msgstr "" "Zugriff zur Weiterleitungs-URL verweigert durch robots.txt; prüfe lediglich " "Syntax." #: ../linkcheck/checker/httpurl.py:139 msgid "syntax OK" msgstr "Syntax OK" #: ../linkcheck/checker/httpurl.py:283 #, fuzzy, python-format msgid "Redirected to `%(url)s' status: %(code)d %(reason)s." msgstr "Zu `%(url)s' umgeleitet." #: ../linkcheck/checker/httpurl.py:336 msgid "OK" msgstr "OK" #: ../linkcheck/checker/dnsurl.py:46 #, python-format msgid "%(host)s resolved to IPs %(ips)s" msgstr "" #: ../linkcheck/checker/dnsurl.py:48 #, fuzzy, python-format msgid "%(host)r could not be resolved" msgstr "Der MX Mail-Rechner konnte nicht gefunden werden." #: ../linkcheck/command/setup_config.py:49 msgid "Running with python -O disables debugging." msgstr "Die Option python -O verhindert das Debuggen." #: ../linkcheck/command/setup_config.py:81 #, python-format msgid "blacklist is deprecated for option %(option)s, using failures instead" msgstr "" #: ../linkcheck/command/setup_config.py:87 #: ../linkcheck/command/setup_config.py:133 #, python-format msgid "Unknown logger type %(type)r in %(output)r for option %(option)s" msgstr "Unbekannter Logtyp %(type)r in %(output)r für Option %(option)s" #: ../linkcheck/command/setup_config.py:94 #: ../linkcheck/command/setup_config.py:144 #, python-format msgid "Unknown encoding %(encoding)r in %(output)r for option %(option)s" msgstr "Unbekanntes Encoding %(encoding)r in %(output)r für Option %(option)s" #: ../linkcheck/command/setup_config.py:127 #, python-format msgid "" "blacklist logger is deprecated for option %(option)s, using failures instead" msgstr "" #: ../linkcheck/command/setup_config.py:159 #, python-format msgid "Enter LinkChecker HTTP/FTP password for user %(user)s:" msgstr "Gebe LinkChecker HTTP/FTP Passwort für Benutzer %(user)s ein:" #: ../linkcheck/command/setup_config.py:163 msgid "Enter LinkChecker HTTP/FTP password:" msgstr "Gebe LinkChecker HTTP/FTP Passwort ein:" #: ../linkcheck/command/setup_config.py:181 #, python-format msgid "Illegal argument %(arg)r for option %(option)s" msgstr "Ungültiges Argument %(arg)r für Option %(option)s" #: ../linkcheck/command/setup_config.py:198 #, python-format msgid "Enter LinkChecker password for user %(user)s at %(strpattern)s:" msgstr "" "Gebe LinkChecker Passwort für Benutzer %(user)s bei %(strpattern)s ein:" #: ../linkcheck/command/setup_config.py:207 #, fuzzy, python-format msgid "Cookie file %s does not exist." msgstr "Konfigurationsdatei %r existiert nicht." #: ../linkcheck/command/setup_config.py:210 #, fuzzy, python-format msgid "Could not read cookie file %s" msgstr "Konnte Cookie-Datei nicht parsen: %s" #: ../linkcheck/command/linkchecker.py:50 msgid "Running as root user; dropping privileges by changing user to nobody." msgstr "" "Laufe als Benutzer root; Privilegien werden aufgegeben indem auf Benutzer " "nobody gewechselt wird." #: ../linkcheck/command/linkchecker.py:124 #, python-format msgid "Invalid debug level %(level)r" msgstr "Ungültiger Debuglevel %(level)r" #: ../linkcheck/command/linkchecker.py:140 #, fuzzy, python-format msgid "Config file %s does not exist." msgstr "Konfigurationsdatei %r existiert nicht." #: ../linkcheck/command/linkchecker.py:143 #, fuzzy, python-format msgid "Could not read config file %s." msgstr "Konnte Cookie-Datei nicht parsen: %s" #: ../linkcheck/command/linkchecker.py:176 msgid "no files or URLs given" msgstr "keine Dateien oder URLs angegeben" #: ../linkcheck/command/linkchecker.py:184 #, python-format msgid "" "Overwrite profiling file %(file)r?\n" "Press Ctrl-C to cancel, RETURN to continue." msgstr "" "Profildatei %(file)r überschreiben?\n" "Drücken Sie Strg-C zum Abbrechen, EINGABETASTE zum Fortfahren." #: ../linkcheck/command/linkchecker.py:192 msgid "Canceled." msgstr "Abgebrochen." #: ../linkcheck/command/linkchecker.py:199 msgid "" "The `yappi' Python module is not installed, therefore the --profile option " "is disabled." msgstr "" "Das `yappi' Python Modul ist nicht installiert, deshalb ist die --profile " "Option deaktiviert." #: ../linkcheck/command/linkchecker.py:218 msgid "Dumping memory statistics..." msgstr "Generiere Speicherabzug..." #: ../linkcheck/command/linkchecker.py:220 #, python-format msgid "The memory dump has been written to `%(filename)s'." msgstr "Der Speicherabzug wurde in Datei `%(filename)s' geschrieben." #: ../linkcheck/command/arg_parser.py:28 #, fuzzy msgid "" "NOTES\n" " o URLs on the command line starting with \"ftp.\" are treated like\n" " \"ftp://ftp.\", URLs starting with \"www.\" are treated like \"http://www." "\".\n" " You can also give local files as arguments.\n" " o If you have your system configured to automatically establish a\n" " connection to the internet (e.g. with diald), it will connect when\n" " checking links not pointing to your local system.\n" " See the --ignore-url option on how to prevent this.\n" " o Javascript links are currently ignored.\n" " o If your platform does not support threading, LinkChecker disables it\n" " automatically.\n" " o You can supply multiple user/password pairs in a configuration file.\n" msgstr "" "KOMMENTARE\n" "o URLs von der Kommandozeile die mit \"ftp.\" beginnen werden wie\n" "\"ftp://ftp.\" behandelt, URLs die mit \"www.\" beginnen wie \"http://www." "\".\n" " Sie können auch lokale Dateien als Argumente angeben.\n" "o Falls sich Ihr System automatisch mit dem Internet verbindet\n" " (z.B. mit diald), wird es dies tun wenn Sie Links prüfen, die nicht\n" " auf Ihren lokalen Rechner verweisen.\n" " Benutzen Sie die Optionen -s und -i um dies zu verhindern.\n" "o Javascript Links werden zur Zeit ignoriert.\n" "o Wenn Ihr System keine Threads unterstützt deaktiviert LinkChecker diese\n" " automatisch.\n" "o Sie können mehrere Benutzer/Passwort Paare in einer Konfigurationsdatei\n" " angeben.\n" "o Beim Prüfen von 'news:' Links muss der angegebene NNTP Rechner nicht\n" " unbedingt derselbe wie der des Benutzers sein.\n" #: ../linkcheck/command/arg_parser.py:44 msgid "" "PROXY SUPPORT\n" "To use a proxy on Unix or Windows set $http_proxy or $https_proxy\n" "to the proxy URL. The URL should be of the form\n" "\"http://[:@][:]\".\n" "LinkChecker also detects manual proxy settings of Internet Explorer under\n" "Windows systems. On a Mac use the Internet Config to select a proxy.\n" "\n" "LinkChecker honors the $no_proxy environment variable. It can be a list\n" "of domain names for which no proxy will be used.\n" "\n" "Setting a HTTP proxy on Unix for example looks like this:\n" "\n" " export http_proxy=\"http://proxy.example.com:8080\"\n" "\n" "Proxy authentication is also supported:\n" "\n" " export http_proxy=\"http://user1:mypass@proxy.example.org:8081\"\n" "\n" "Setting a proxy on the Windows command prompt:\n" "\n" " set http_proxy=http://proxy.example.com:8080\n" "\n" msgstr "" "PROXY-UNTERSTÜTZUNG\n" "Um einen Proxy unter Unix oder Windows zu benutzen, setzen Sie $http_proxy " "oder $https_proxy\n" "auf die Proxy URL. Die URL sollte die Form \"http://[:@][:" "]\"\n" "besitzen.\n" "LinkChecker erkennt auch die Proxy-Einstellungen des Internet Explorers auf " "einem\n" "Windows-System. Auf einem Mac benutzen Sie die Internet Konfiguration.\n" "\n" "LinkChecker beachtet die Umgebungsvariable $no_proxy. Diese kann eine Liste " "von\n" "Domänennamen beinhalten, für die kein Proxy benutzt wird.\n" "\n" "Einen HTTP-Proxy unter Unix anzugeben sieht beispielsweise so aus:\n" "\n" " export http_proxy=\"http://proxy.example.com:8080\"\n" "\n" "Proxy-Authentifizierung wird ebenfalls unterstützt:\n" "\n" " export http_proxy=\"http://user1:mypass@proxy.example.org:8081\"\n" "\n" "Setzen eines Proxies unter der Windows Befehlszeile:\n" "\n" " set http_proxy=http://proxy.example.com:8080\n" "\n" #: ../linkcheck/command/arg_parser.py:70 msgid "" "REGULAR EXPRESSIONS\n" "Only Python regular expressions are accepted by LinkChecker.\n" "See https://docs.python.org/howto/regex.html for an introduction in\n" "regular expressions.\n" "\n" "The only addition is that a leading exclamation mark negates\n" "the regular expression.\n" msgstr "" "REGULÄRE AUSDRÜCKE\n" "Lediglich Pythons reguläre Ausdrücke werden von LinkChecker akzeptiert.\n" "Siehe https://docs.python.org/howto/regex.html für eine Einführung in\n" "reguläre Ausdrücke.\n" "\n" "Die einzige Hinzufügung ist, dass ein regulärer Ausdruck negiert wird\n" "falls er mit einem Ausrufezeichen beginnt.\n" #: ../linkcheck/command/arg_parser.py:81 msgid "" "COOKIE FILES\n" "A cookie file contains standard RFC 805 header data with the following\n" "possible names:\n" "Scheme (optional)\n" " Sets the scheme the cookies are valid for; default scheme is 'http'.\n" "Host (required)\n" " Sets the domain the cookies are valid for.\n" "Path (optional)\n" " Gives the path the cookies are value for; default path is '/'.\n" "Set-cookie (optional)\n" " Set cookie name/value. Can be given more than once.\n" "\n" "Multiple entries are separated by a blank line.\n" "\n" "The example below will send two cookies to all URLs starting with\n" "'http://example.org/hello/' and one to all URLs starting\n" "with 'https://example.com/':\n" "\n" "Host: example.org\n" "Path: /hello\n" "Set-cookie: ID=\"smee\"\n" "Set-cookie: spam=\"egg\"\n" "\n" "Scheme: https\n" "Host: example.com\n" "Set-cookie: baggage=\"elitist\"; comment=\"hologram\"\n" msgstr "" "COOKIE-DATEIEN\n" "Eine Cookie-Datei enthält Standard RFC 805 Kopfdaten mit den folgenden\n" "möglichen Namen:\n" "Scheme (optional)\n" " Setzt das Schema für das die Cookies gültig sind; Standardschema ist " "'http'.\n" "Host (erforderlich)\n" " Setzt die Domäne für die die Cookies gültig sind.\n" "Path (optional)\n" " Gibt den Pfad für den die Cookies gültig sind; Standardpfad ist '/'.\n" "Set-cookie (optional)\n" " Setzt den Cookie Name/Wert. Kann mehrmals angegeben werden.\n" "\n" "Mehrere Einträge können sind durch eine Leerzeile zu trennen.\n" "\n" "Das untige Beispiel sendet zwei Cookies zu allen URLs die mit\n" "'http://example.org/hello/' beginnen, und eins zu allen URLs die mit\n" "'https://example.com' beginnen:\n" "\n" "Host: example.org\n" "Path: /hello\n" "Set-cookie: ID=\"smee\"\n" "Set-cookie: spam=\"egg\"\n" "\n" "Scheme: https\n" "Host: example.com\n" "Set-cookie: baggage=\"elitist\"; comment=\"hologram\"\n" #: ../linkcheck/command/arg_parser.py:111 msgid "" "RETURN VALUE\n" "The return value is non-zero when\n" " o invalid links were found or\n" " o warnings were found warnings are enabled\n" " o a program error occurred\n" msgstr "" "RÜCKGABEWERT\n" "Der Rückgabewert ist nicht Null falls\n" " o ungültige Verknüpfungen gefunden wurden oder\n" " o Warnungen gefunden wurden und Warnungen aktiviert sind\n" " o ein Programmfehler aufgetreten ist\n" #: ../linkcheck/command/arg_parser.py:120 msgid "" "EXAMPLES\n" "The most common use checks the given domain recursively, plus any\n" "single URL pointing outside of the domain:\n" " linkchecker http://www.example.org/\n" "Beware that this checks the whole site which can have several hundred\n" "thousands URLs. Use the -r option to restrict the recursion depth.\n" "\n" "Don't connect to mailto: hosts, only check their URL syntax. All other\n" "links are checked as usual:\n" " linkchecker --ignore-url=^mailto: www.example.org\n" "\n" "Checking local HTML files on Unix:\n" " linkchecker ../bla.html subdir/blubber.html\n" "\n" "Checking a local HTML file on Windows:\n" " linkchecker c:\\temp\\test.html\n" "\n" "You can skip the \"http://\" url part if the domain starts with \"www.\":\n" " linkchecker www.example.de\n" "\n" "You can skip the \"ftp://\" url part if the domain starts with \"ftp.\":\n" " linkchecker -r0 ftp.example.org\n" msgstr "" "BEISPIELE\n" "Der häufigste Gebrauch prüft die angegebene Domäne rekursiv, inklusive " "aller\n" "einzelnen URLs die außerhalb dieser Domäne zeigen:\n" " linkchecker http://www.example.de/\n" "Beachten Sie, dass diese Prüfung die komplette Website abprüft, welche " "mehrere\n" "Hunderttausend URLs besitzen kann. Benutzen Sie die Option -r, um die\n" "Rekursionstiefe einzuschränken.\n" "\n" "Keine Verbindung zu mailto: Rechner aufbauen, prüfe lediglich deren URL\n" "Syntax. Alle anderen Links werden wie üblich geprüft:\n" " linkchecker --ignore-url=^mailto: www.example.org\n" "\n" "Prüfe eine lokale HTML Datei unter UNIX:\n" " linkchecker ../bla.html subdir/blubber.html\n" "\n" "Prüfe eine lokale HTML Datei unter Windows:\n" " linkchecker c:\\temp\\test.html\n" "\n" "Sie können den \"http://\" Teil der URL weglassen wenn die Domäne mit\n" "\"www.\" beginnt:\n" " linkchecker www.example.de\n" "\n" "Sie können den \"ftp://\" Teil der URL weglassen wenn die Domäne mit\n" "\"ftp.\" beginnt:\n" " linkchecker -r0 ftp.example.org\n" #: ../linkcheck/command/arg_parser.py:146 msgid "" "OUTPUT TYPES\n" "Note that by default only errors and warnings are logged.\n" "You should use the --verbose option to see valid URLs,\n" "and when outputting a sitemap graph format.\n" "\n" "text Standard text output, logging URLs in keyword: argument fashion.\n" "html Log URLs in keyword: argument fashion, formatted as HTML.\n" " Additionally has links to the referenced pages. Invalid URLs have\n" " HTML and CSS syntax check links appended.\n" "csv Log check result in CSV format with one URL per line.\n" "gml Log parent-child relations between linked URLs as a GML sitemap\n" " graph.\n" "dot Log parent-child relations between linked URLs as a DOT sitemap\n" " graph.\n" "gxml Log check result as a GraphXML sitemap graph.\n" "xml Log check result as machine-readable XML.\n" "sql Log check result as SQL script with INSERT commands. An example\n" " script to create the initial SQL table is included as create.sql.\n" "failures\n" " Suitable for cron jobs. Logs the check result into a file\n" " $XDG_DATA_HOME/linkchecker/failures which only contains entries " "with\n" " invalid URLs and the number of times they have failed.\n" "none Logs nothing. Suitable for debugging or checking the exit code.\n" msgstr "" "AUSGABETYPEN\n" "Beachten Sie, dass normalerweise nur Fehler und Warnungen ausgegeben " "werden.\n" "Sie sollten die Option --verbose benutzen, um gültige URLs zu sehen,\n" "und wenn Sie ein Graphformat ausgeben lassen.\n" "\n" "text Standard Textausgabe in \"Schlüssel: Wert\"-Form.\n" "html Gebe URLs in \"Schlüssel: Wert\"-Form als HTML formatiert aus.\n" " Besitzt zudem Verknüpfungen auf die referenzierten Seiten. Ungültige " "URLs haben\n" " Verknüpfungen zur HTML und CSS Syntaxprüfung angehängt.\n" "csv Gebe Prüfresultat in CSV-Format aus mit einer URL pro Zeile.\n" "gml Gebe Eltern-Kind Beziehungen zwischen verknüpften URLs als GML " "Graphen aus.\n" "dot Gebe Eltern-Kind Beziehungen zwischen verknüpften URLs als DOT " "Graphen aus.\n" "gxml Gebe Prüfresultat als GraphXML-Datei aus.\n" "xml Gebe Prüfresultat als maschinenlesbare XML-Datei aus.\n" "sql Gebe Prüfresultat als SQL Skript mit INSERT Befehlen aus. Ein " "Beispielskript,\n" " um die initiale SQL Tabelle zu erstellen ist unter create.sql zu " "finden.\n" "failures\n" " Für Cronjobs geeignet. Gibt das Prüfergebnis in eine Datei " "$XDG_DATA_HOME/linkchecker/failures aus,\n" " welche nur Einträge mit fehlerhaften URLs und die Anzahl der " "Fehlversuche\n" " enthält.\n" "none Gibt nichts aus. Für Debugging oder Prüfen des Rückgabewerts " "geeignet.\n" #: ../linkcheck/command/arg_parser.py:174 msgid "" "IGNORE WARNINGS\n" "The following warnings are recognized in the 'ignorewarnings' config\n" "file entry:\n" msgstr "" "WARNUNGEN IGNORIEREN\n" "Die folgenden Warnungen werden vom Konfigurationseintrag 'ignorewarnings'\n" "erkannt:\n" #: ../linkcheck/command/arg_parser.py:212 msgid "General options" msgstr "Allgemeine Optionen" #: ../linkcheck/command/arg_parser.py:219 #, python-format msgid "" "Use FILENAME as configuration file. Per default LinkChecker uses\n" "$XDG_CONFIG_HOME/linkchecker/linkcheckerrc (under Windows\n" "%%HOMEPATH%%\\.config\\linkchecker\\linkcheckerrc)." msgstr "" "Benutze FILENAME als Konfigurationsdatei. Standardmäßig benutzt\n" " LinkChecker $XDG_CONFIG_HOME/linkchecker/linkcheckerrc\n" "(unter Windows %%HOMEPATH%%\\.config\\linkchecker\\linkcheckerrc)." #: ../linkcheck/command/arg_parser.py:230 msgid "" "Generate no more than the given number of threads. Default number\n" "of threads is 10. To disable threading specify a non-positive number." msgstr "" "Generiere nicht mehr als die angegebene Anzahl von Threads. Standard Anzahl " "von Threads ist 10. Geben Sie eine negative Zahl an, um Threading zu " "deaktivieren." #: ../linkcheck/command/arg_parser.py:235 msgid "Print version and exit." msgstr "Drucke die Version und beende das Programm." #: ../linkcheck/command/arg_parser.py:241 #, fuzzy msgid "Print available check plugins and exit." msgstr "Drucke die Version und beende das Programm." #: ../linkcheck/command/arg_parser.py:246 msgid "Read list of white-space separated URLs to check from stdin." msgstr "" "Lese eine Liste von URLs zum Prüfen von der Standardeingabe, getrennt durch " "Leerzeichen." #: ../linkcheck/command/arg_parser.py:250 msgid "Output options" msgstr "Ausgabeoptionen" #: ../linkcheck/command/arg_parser.py:257 #, python-format msgid "" "Print debugging output for the given logger.\n" "Available loggers are %(lognamelist)s.\n" "Specifying 'all' is an alias for specifying all available loggers.\n" "The option can be given multiple times to debug with more\n" "than one logger.\n" "\n" "For accurate results, threading will be disabled during debug runs." msgstr "" "Gebe Debugmeldungen aus für den angegebenen Logger.\n" "Verfügbare Logger sind %(lognamelist)s.\n" " Die Angabe\n" "'all' ist ein Synonym für alle verfügbaren Logger.\n" "Diese Option kann mehrmals angegeben werden, um\n" "mit mehr als einem Logger zu debuggen.\n" "\n" "Für exakte Resultate wird Threading während Debugläufen deaktiviert." #: ../linkcheck/command/arg_parser.py:274 #, python-format msgid "" "Output to a file linkchecker-out.TYPE, $XDG_DATA_HOME/linkchecker/failures " "for\n" "'failures' output, or FILENAME if specified.\n" "The ENCODING specifies the output encoding, the default is that of your\n" "locale.\n" "Valid encodings are listed at https://docs.python.org/library/codecs." "html#standard-encodings.\n" "The FILENAME and ENCODING parts of the 'none' output type will be ignored,\n" "else if the file already exists, it will be overwritten.\n" "You can specify this option more than once. Valid file output types\n" "are %(loggertypes)s. You can specify this option multiple times to output\n" "to more than one file. Default is no file output. Note that you can\n" "suppress all console output with the option '-o none'." msgstr "" "Ausgabe in eine Datei namens linkchecker-out.TYPE,\n" "$XDG_DATA_HOME/linkchecker/failures\n" "bei 'failures' Ausgabe, oder FILENAME falls angegeben.\n" "Das ENCODING gibt die Ausgabeenkodierung an, der Standard ist die\n" "Enkodierung der ausgewählten Spracheinstellung.\n" "Gültige Enkodierungen sind unter https://docs.python.org/library/codecs." "html#standard-encodings aufgeführt.\n" "Der FILENAME und ENCODING Teil wird bei dem Ausgabetyp 'none' ignoriert,\n" "ansonsten wird die Datei überschreiben falls sie existiert.\n" "Sie können diese Option mehr als einmal verwenden. Gültige\n" "Ausgabetypen sind %(loggertypes)s.\n" "Standard ist keine Dateiausgabe. Beachten Sie dass die Option\n" "'-o none' jegliche Ausgaben auf der Konsole verhindert." #: ../linkcheck/command/arg_parser.py:294 msgid "Do not print check status messages." msgstr "Gebe keine Statusmeldungen aus." #: ../linkcheck/command/arg_parser.py:300 msgid "Don't log warnings. Default is to log warnings." msgstr "Gebe keine Warnungen aus. Standard ist die Ausgabe von Warnungen." #: ../linkcheck/command/arg_parser.py:308 #, python-format msgid "" "Specify output as %(loggertypes)s. Default output type is text.\n" "The ENCODING specifies the output encoding, the default is that of your\n" "locale.\n" "Valid encodings are listed at https://docs.python.org/library/codecs." "html#standard-encodings." msgstr "" "Spezifiziere die Ausgabe als %(loggertypes)s. Standardausgabe ist text. Das " "ENCODING gibt die Ausgabeenkodierung an, der Standard ist die\n" "Enkodierung der ausgewählten Spracheinstellung.\n" "Gültige Enkodierungen sind unter https://docs.python.org/library/codecs." "html#standard-encodings aufgeführt." #: ../linkcheck/command/arg_parser.py:325 msgid "" "Quiet operation, an alias for '-o none'.\n" "This is only useful with -F." msgstr "" "Keine Ausgabe, ein Alias für '-o none'.\n" "Dies ist nur in Verbindung mit -F nützlich." #: ../linkcheck/command/arg_parser.py:336 msgid "Log all URLs. Default is to log only errors and warnings." msgstr "Logge alle URLs. Standard ist es, nur fehlerhafte URLs zu loggen." #: ../linkcheck/command/arg_parser.py:340 msgid "Checking options" msgstr "Prüf-Optionen" #: ../linkcheck/command/arg_parser.py:346 msgid "" "Read a file with initial cookie data. The cookie data format is\n" "explained below." msgstr "" "Lese eine Datei mit Cookie-Daten. Das Datenformat\n" "ist weiter unten erklärt." #: ../linkcheck/command/arg_parser.py:356 msgid "Disable robots.txt checks" msgstr "" #: ../linkcheck/command/arg_parser.py:362 msgid "Check external URLs." msgstr "" #: ../linkcheck/command/arg_parser.py:370 #, fuzzy msgid "" "Only check syntax of URLs matching the given regular expression.\n" "This option can be given multiple times." msgstr "" "Prüfe lediglich den Syntax der URLs, welche auf den angegebenen regulären " "Ausdruck zutreffen. Diese Option kann mehrmals angegebenen werden." #: ../linkcheck/command/arg_parser.py:380 msgid "" "Check but do not recurse into URLs matching the given regular\n" "expression. This option can be given multiple times." msgstr "" "Prüfe URLs die auf den angegebenen regulären Ausdruck zutreffen, aber steige " "nicht rekursiv in sie hinab. Diese Option kann mehrmals angegeben werden." #: ../linkcheck/command/arg_parser.py:390 msgid "" "Read a password from console and use it for HTTP and FTP authorization.\n" "For FTP the default password is 'anonymous@'. For HTTP there is\n" "no default password. See also -u." msgstr "" "Lese ein Passwort von der Kommandozeile und verwende es für HTTP und FTP " "Authorisation.\n" "Für FTP ist das Standardpasswort 'anonymous@'. Für HTTP gibt es kein " "Standardpasswort.\n" "Siehe auch -u." #: ../linkcheck/command/arg_parser.py:402 msgid "" "Check recursively all links up to given depth. A negative depth\n" "will enable infinite recursion. Default depth is infinite." msgstr "" "Prüfe rekursiv alle Verknüpfungen bis zu der angegebenen Tiefe. Eine\n" "negative Tiefe erwirkt unendliche Rekursion. Standard Tiefe ist\n" "unendlich." #: ../linkcheck/command/arg_parser.py:412 #, fuzzy msgid "Set the timeout for connection attempts in seconds." msgstr "" "Setze den Timeout für Verbindungen in Sekunden. Der Standard\n" "Timeout ist %d Sekunden." #: ../linkcheck/command/arg_parser.py:421 msgid "" "Try the given username for HTTP and FTP authorization.\n" "For FTP the default username is 'anonymous'. For HTTP there is\n" "no default username. See also -p." msgstr "" "Verwende den angegebenen Benutzernamen für HTTP und FTP\n" "Authorisation. Für FTP ist der Standardname 'anonymous'. Für HTTP gibt es " "kein Standardnamen. Siehe auch -p." #: ../linkcheck/command/arg_parser.py:431 msgid "" "Specify the User-Agent string to send to the HTTP server, for example\n" "\"Mozilla/4.0\". The default is \"LinkChecker/X.Y\" where X.Y is the " "current\n" "version of LinkChecker." msgstr "" "Gibt den User-Agent an, der zu HTTP-Servern geschickt wird,\n" "z.B. \"Mozilla/4.0\". Der Standard ist \"LinkChecker/X.Y\", wobei X.Y\n" "die aktuelle Version von LinkChecker ist." #: ../linkcheck/logger/html.py:127 ../linkcheck/logger/text.py:112 #, python-format msgid "Start checking at %s" msgstr "Beginne Prüfen am %s" #: ../linkcheck/logger/html.py:203 ../linkcheck/logger/text.py:165 #, python-format msgid ", line %d" msgstr ", Zeile %d" #: ../linkcheck/logger/html.py:205 ../linkcheck/logger/text.py:167 #, python-format msgid ", col %d" msgstr ", Spalte %d" #: ../linkcheck/logger/html.py:207 ../linkcheck/logger/text.py:169 #, fuzzy, python-format msgid ", page %d" msgstr ", Zeile %d" #: ../linkcheck/logger/html.py:246 ../linkcheck/logger/html.py:266 #: ../linkcheck/logger/text.py:185 ../linkcheck/logger/text.py:195 #, python-format msgid "%.3f seconds" msgstr "%.3f Sekunden" #: ../linkcheck/logger/html.py:311 ../linkcheck/logger/text.py:218 msgid "Valid" msgstr "Gültig" #: ../linkcheck/logger/html.py:316 ../linkcheck/logger/text.py:221 msgid "Error" msgstr "Fehler" #: ../linkcheck/logger/html.py:323 msgid "Statistics" msgstr "Statistik" #: ../linkcheck/logger/html.py:327 ../linkcheck/logger/text.py:300 #, python-format msgid "" "Content types: %(image)d image, %(text)d text, %(video)d video, %(audio)d " "audio, %(application)d application, %(mail)d mail and %(other)d other." msgstr "" "Inhalte: %(image)d Bild, %(text)d Text, %(video)d Video, %(audio)d Audio, " "%(application)d Anwendung, %(mail)d E-Mail und %(other)d andere Inhalte." #: ../linkcheck/logger/html.py:335 ../linkcheck/logger/text.py:307 #, python-format msgid "URL lengths: min=%(min)d, max=%(max)d, avg=%(avg)d." msgstr "URL Längen: min=%(min)d, max=%(max)d, mittel=%(avg)d" #: ../linkcheck/logger/html.py:343 ../linkcheck/logger/text.py:315 msgid "No statistics available since no URLs were checked." msgstr "Keine Statistik verfügbar, da keine URLs geprüft wurden." #: ../linkcheck/logger/html.py:349 ../linkcheck/logger/text.py:231 msgid "That's it." msgstr "Das war's." #: ../linkcheck/logger/html.py:352 #, python-format msgid "%d link checked." msgid_plural "%d links checked." msgstr[0] "%d Verknüpfung überprüft." msgstr[1] "%d Verknüpfungen überprüft." #: ../linkcheck/logger/html.py:357 ../linkcheck/logger/text.py:240 #, python-format msgid "%d warning found" msgid_plural "%d warnings found" msgstr[0] "%d Warnung gefunden" msgstr[1] "%d Warnungen gefunden" #: ../linkcheck/logger/html.py:362 ../linkcheck/logger/text.py:250 #, python-format msgid " (%d ignored or duplicates not printed)" msgstr " (%d ignorierte oder doppelte Vorkommen nicht ausgegeben)" #: ../linkcheck/logger/html.py:367 ../linkcheck/logger/text.py:255 #, python-format msgid "%d error found" msgid_plural "%d errors found" msgstr[0] "%d Fehler gefunden" msgstr[1] "%d Fehler gefunden" #: ../linkcheck/logger/html.py:372 ../linkcheck/logger/text.py:265 #, python-format msgid " (%d duplicates not printed)" msgstr " (%d doppelte Vorkommen nicht ausgegeben)" #: ../linkcheck/logger/html.py:381 ../linkcheck/logger/text.py:273 #, python-format msgid "There was %(num)d internal error." msgid_plural "There were %(num)d internal errors." msgstr[0] "Es gab %(num)d internen Fehler." msgstr[1] "Es gab %(num)d interne Fehler." #: ../linkcheck/logger/html.py:391 ../linkcheck/logger/__init__.py:397 #: ../linkcheck/logger/text.py:282 #, python-format msgid "Stopped checking at %(time)s (%(duration)s)" msgstr "Beende Prüfen am %(time)s (%(duration)s)" #: ../linkcheck/logger/html.py:401 #, fuzzy, python-format msgid "Read the documentation at %s" msgstr "Die neueste Version gibt es unter %s" #: ../linkcheck/logger/html.py:411 #, python-format msgid "Write comments and bugs to %s" msgstr "Schreiben Sie Kommentare und Fehler an %s" #: ../linkcheck/logger/failures.py:47 #, python-format msgid "%(blacklist)s file is deprecated please rename to failures" msgstr "" #: ../linkcheck/logger/failures.py:99 #, python-format msgid "invalid line starting with '%(linestart)s' in %(failures)s" msgstr "" #: ../linkcheck/logger/__init__.py:31 msgid "Real URL" msgstr "Tats. URL" #: ../linkcheck/logger/__init__.py:32 msgid "Cache key" msgstr "Cache Schlüssel" #: ../linkcheck/logger/__init__.py:33 msgid "Result" msgstr "Ergebnis" #: ../linkcheck/logger/__init__.py:34 msgid "Base" msgstr "Basis" #: ../linkcheck/logger/__init__.py:35 msgid "Name" msgstr "Name" #: ../linkcheck/logger/__init__.py:36 msgid "Parent URL" msgstr "Eltern URL" #: ../linkcheck/logger/__init__.py:37 msgid "Extern" msgstr "Extern" #: ../linkcheck/logger/__init__.py:38 msgid "Info" msgstr "Info" #: ../linkcheck/logger/__init__.py:39 msgid "Warning" msgstr "Warnung" #: ../linkcheck/logger/__init__.py:40 msgid "D/L time" msgstr "D/L Zeit" #: ../linkcheck/logger/__init__.py:41 msgid "Size" msgstr "Größe" #: ../linkcheck/logger/__init__.py:42 msgid "Check time" msgstr "Prüfzeit" #: ../linkcheck/logger/__init__.py:43 msgid "URL" msgstr "URL" #: ../linkcheck/logger/__init__.py:44 msgid "Level" msgstr "Tiefe" #: ../linkcheck/logger/__init__.py:45 msgid "Modified" msgstr "Geändert" #: ../linkcheck/logger/__init__.py:275 #, python-format msgid "Happy birthday for LinkChecker, I'm %d years old today!" msgstr "" "Herzlichen Glückwunsch zum Geburtstag, LinkChecker, ich bin heute %d Jahre " "alt geworden!" #: ../linkcheck/logger/__init__.py:381 #, python-format msgid "created by %(app)s at %(time)s" msgstr "erstellt von %(app)s am %(time)s" #: ../linkcheck/logger/__init__.py:385 ../linkcheck/logger/text.py:105 #, fuzzy, python-format msgid "Read the documentation at %(url)s" msgstr "Die neueste Version gibt es unter %(url)s" #: ../linkcheck/logger/__init__.py:388 ../linkcheck/logger/text.py:108 #, python-format msgid "Write comments and bugs to %(url)s" msgstr "Schreiben Sie Kommentare und Fehler an %(url)s" #: ../linkcheck/logger/text.py:65 msgid "Invalid value for wraplength. Using default." msgstr "" #: ../linkcheck/logger/text.py:230 msgid "The check has been interrupted; results are not complete." msgstr "" #: ../linkcheck/logger/text.py:232 #, python-format msgid "%d link" msgid_plural "%d links" msgstr[0] "%d Verknüpfung" msgstr[1] "%d Verknüpfungen" #: ../linkcheck/logger/text.py:236 #, fuzzy, python-format msgid "in %d URL" msgid_plural "in %d URLs" msgstr[0] "Gültige URLs" msgstr[1] "Gültige URLs" #: ../linkcheck/logger/text.py:238 msgid " checked." msgstr " überprüft." #: ../linkcheck/logger/text.py:292 msgid "Statistics:" msgstr "Statistik:" #: ../linkcheck/logger/text.py:295 #, python-format msgid "Downloaded: %s." msgstr "Heruntergeladen: %s." #: ../linkcheck/__init__.py:77 #, python-format msgid "Link pattern %r strict=%s" msgstr "" #: ../linkcheck/__init__.py:87 #, fuzzy, python-format msgid "invalid regular expression %r: %s" msgstr "ungültiger Rekursionslevel %r" #: ../linkcheck/__init__.py:111 msgid "CRITICAL" msgstr "KRITISCH" #: ../linkcheck/__init__.py:112 msgid "ERROR" msgstr "FEHLER" #: ../linkcheck/__init__.py:113 msgid "WARN" msgstr "WARN" #: ../linkcheck/__init__.py:114 msgid "WARNING" msgstr "WARNUNG" #: ../linkcheck/__init__.py:115 msgid "INFO" msgstr "INFO" #: ../linkcheck/__init__.py:116 msgid "DEBUG" msgstr "DEBUG" #: ../linkcheck/__init__.py:117 msgid "NOTSET" msgstr "NICHTS" #: ../linkcheck/strformat.py:165 #, python-format msgid "%(prefix)s%(duration).02f seconds" msgstr "%(prefix)s%(duration).02f Sekunden" #: ../linkcheck/strformat.py:170 #, python-format msgid "%d second" msgid_plural "%d seconds" msgstr[0] "%d Sekunde" msgstr[1] "%d Sekunden" #: ../linkcheck/strformat.py:171 #, python-format msgid "%d minute" msgid_plural "%d minutes" msgstr[0] "%d Minute" msgstr[1] "%d Minuten" #: ../linkcheck/strformat.py:172 #, python-format msgid "%d hour" msgid_plural "%d hours" msgstr[0] "%d Stunde" msgstr[1] "%d Stunden" #: ../linkcheck/strformat.py:173 #, python-format msgid "%d day" msgid_plural "%d days" msgstr[0] "%d Tag" msgstr[1] "%d Tage" #: ../linkcheck/strformat.py:174 #, python-format msgid "%d year" msgid_plural "%d years" msgstr[0] "%d Jahr" msgstr[1] "%d Jahre" #: ../linkcheck/strformat.py:245 #, python-format msgid "" "Could not import %(module)s for %(feature)s. Install %(module)s from %(url)s " "to use this feature." msgstr "" "Konnte Modul %(module)s für %(feature)s nicht importieren. Installieren Sie " "%(module)s von %(url)s, um dieses Feature zu nutzen." #: ../linkcheck/cache/robots_txt.py:77 #, python-format msgid "Relative Sitemap %s in %s discarded" msgstr "" #: ../linkcheck/loader.py:40 #, python-format msgid "WARN: could not load module %s: %s" msgstr "" #: ../linkcheck/loader.py:57 #, fuzzy, python-format msgid "WARN: could not load file %s: %s" msgstr "Konnte Cookie-Datei nicht parsen: %s" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:228 #, python-format msgid "%(heading)s:" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:300 #, fuzzy msgid "usage: " msgstr "Syntax: %s\n" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:726 #, python-format msgid " (default: %(default)s)" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:780 #, python-format msgid "argument %(argument_name)s: %(message)s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:886 msgid ".__call__() not defined" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1157 msgid "show program's version number and exit" msgstr "Zeige Programmversion und beende" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1219 #, python-format msgid "conflicting subparser: %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1223 #, python-format msgid "conflicting subparser alias: %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1258 #, python-format msgid "unknown parser %(parser_name)r (choices: %(choices)s)" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1318 #, python-format msgid "argument \"-\" with mode %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1327 #, python-format msgid "can't open '%(filename)s': %(error)s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1536 #, python-format msgid "cannot merge actions - two groups are named %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1574 msgid "'required' is an invalid argument for positionals" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1596 #, python-format msgid "" "invalid option string %(option)r: must start with a character " "%(prefix_chars)r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1614 #, python-format msgid "dest= is required for options like %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1631 #, fuzzy, python-format msgid "invalid conflict_resolution value: %r" msgstr "ungültiger \"notAfter\" Zertifikatwert %r" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1649 #, python-format msgid "conflicting option string: %s" msgid_plural "conflicting option strings: %s" msgstr[0] "" msgstr[1] "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1723 msgid "mutually exclusive arguments must be optional" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1799 #, fuzzy msgid "positional arguments" msgstr "%s Option erfordert ein Argument" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1800 #, fuzzy msgid "options" msgstr "Ausgabeoptionen" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1815 msgid "show this help message and exit" msgstr "Zeige diesen Hilfetext und beende" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1846 msgid "cannot have multiple subparser arguments" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1898 #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2421 #, python-format msgid "unrecognized arguments: %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2001 #, python-format msgid "not allowed with argument %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2043 #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2074 #, python-format msgid "ignored explicit argument %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2181 #, python-format msgid "the following arguments are required: %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2196 #, python-format msgid "one of the arguments %s is required" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2240 msgid "expected one argument" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2241 msgid "expected at most one argument" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2242 msgid "expected at least one argument" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2246 #, python-format msgid "expected %s argument" msgid_plural "expected %s arguments" msgstr[0] "" msgstr[1] "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2303 #, fuzzy, python-format msgid "ambiguous option: %(option)s could match %(matches)s" msgstr "Mehrdeutige Option: %s (%s?)" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2364 #, python-format msgid "unexpected option string: %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2566 #, python-format msgid "%r is not callable" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2582 #, fuzzy, python-format msgid "invalid %(type)s value: %(value)r" msgstr "Option %s: Ungültiger %s Wert: %r" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2593 #, fuzzy, python-format msgid "invalid choice: %(value)r (choose from %(choices)s)" msgstr "Option %s: ungültige Auswahl: %r (wähle von %s)" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2671 #, fuzzy, python-format msgid "%(prog)s: error: %(message)s\n" msgstr "ignore%d: Syntaxfehler %s\n" #, python-format #~ msgid "Unreadable config file: %r" #~ msgstr "Nicht lesbare Konfigurationsdatei: %r" #~ msgid "The NNTP newsgroup could not be found." #~ msgstr "Die NNTP Nachrichtengruppe konnte nicht gefunden werden." #~ msgid "No NNTP server was specified, skipping this URL." #~ msgstr "Kein NNTP Server angegeben; prüfe lediglich Syntax." #, python-format #~ msgid "Article number %(num)s found." #~ msgstr "Artikel Nummer %(num)s wurde gefunden." #, python-format #~ msgid "News group %(name)s found." #~ msgstr "Nachrichtengruppe %(name)s gefunden." #~ msgid "No newsgroup specified in NNTP URL." #~ msgstr "Keine Newsgroup in der NNTP URL spezifiziert." #, python-format #~ msgid "NNTP server too busy; tried more than %d times." #~ msgstr "NNTP Server zu beschäftigt; habe es mehr als %d mal versucht." #~ msgid "Host is empty" #~ msgstr "Rechnername ist leer" #~ msgid "" #~ "Specify an NNTP server for 'news:...' links. Default is the\n" #~ "environment variable NNTP_SERVER. If no host is given,\n" #~ "only the syntax of the link is checked." #~ msgstr "" #~ "Gibt ein NNTP Rechner für 'news:...' Links. Standard ist die\n" #~ "Umgebungsvariable NNTP_SERVER. Falls kein Rechner angegeben ist,\n" #~ "wird lediglich auf korrekte Syntax des Links geprüft." #~ msgid "Default locale:" #~ msgstr "Standard Locale:" #, fuzzy #~ msgid "optional arguments" #~ msgstr "%s Option erfordert ein Argument" #~ msgid "The URL has been ignored." #~ msgstr "Die URL wurde ignoriert." #, fuzzy #~ msgid "Anchor check plugin is broken. Fixes welcome." #~ msgstr "tidy HTML Parser verursachte Fehler: %(msg)s" #~ msgid "Proxy value `%(proxy)s' must start with 'http:' or 'https:'." #~ msgstr "Proxy `%(proxy)s' muss mit 'http:' oder 'https:' beginnen." #~ msgid "Ignoring proxy setting `%(proxy)s'." #~ msgstr "Ignoriere Proxy Einstellung `%(proxy)s'" #~ msgid "Using proxy `%(proxy)s'." #~ msgstr "Verwende Proxy `%(proxy)s'." #~ msgid "no CGI password fieldname given for login URL." #~ msgstr " kein CGI Passwort Feldname für Login URL angegeben." #~ msgid "no CGI user fieldname given for login URL." #~ msgstr "kein CGI Benutzer Feldname für Login URL angegeben." #~ msgid "Support this project at %s" #~ msgstr "Unterstütze dieses Projekt unter %s" #~ msgid "Support this project at %(url)s" #~ msgstr "Unterstütze dieses Projekt unter %(url)s" linkchecker-10.5.0/po/es.po000066400000000000000000001624441466565367000155010ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) 2005-2011 Bastian Kleineidam # This file is distributed under the same license as the linkchecker package. # Servilio Afre Puentes , 2005. # msgid "" msgstr "" "Project-Id-Version: LinkChecker\n" "Report-Msgid-Bugs-To: https://github.com/linkchecker/linkchecker\n" "POT-Creation-Date: 2024-08-27 18:47+0000\n" "PO-Revision-Date: 2011-02-16 15:24+0100\n" "Last-Translator: Bastian Kleineidam \n" "Language-Team: Spanish \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(1 < n);\n" #: ../linkcheck/director/__init__.py:36 #, python-format msgid "Problem using login URL: %(msg)s." msgstr "" #: ../linkcheck/director/__init__.py:39 #, python-format msgid "Error using login URL: %(msg)s." msgstr "" #: ../linkcheck/director/__init__.py:44 #, python-format msgid "Error starting log output: %(msg)s." msgstr "" #: ../linkcheck/director/__init__.py:60 msgid "" "Could not start a new thread. Check that the current user is allowed to " "start new threads." msgstr "" #: ../linkcheck/director/__init__.py:93 #, fuzzy msgid "interrupt; waiting for active threads to finish" msgstr "interrupción por teclado, esperando a que termine %d hilo activo" #: ../linkcheck/director/__init__.py:94 msgid "another interrupt will exit immediately" msgstr "" #: ../linkcheck/director/__init__.py:110 msgid "user abort; force shutdown" msgstr "" #: ../linkcheck/director/aggregator.py:54 #, fuzzy, python-format msgid "Could not parse cookie file: %s. %s" msgstr "No se pudieron almacenar las \"cookies\": %s." #: ../linkcheck/director/aggregator.py:188 msgid "These URLs are still active:" msgstr "" #: ../linkcheck/director/aggregator.py:200 #, python-format msgid "" "%(num)d URLs are still active. After a timeout of %(timeout)s the active " "URLs will stop." msgstr "" #: ../linkcheck/director/console.py:38 #, fuzzy, python-format msgid "%2d thread active" msgid_plural "%2d threads active" msgstr[0] "%2d hilo activo" msgstr[1] "%2d hilos activos" #: ../linkcheck/director/console.py:40 #, fuzzy, python-format msgid "%5d link queued" msgid_plural "%5d links queued" msgstr[0] "%5d URL encolado" msgstr[1] "%5d URLs encolados" #: ../linkcheck/director/console.py:42 #, python-format msgid "%4d link" msgid_plural "%4d links" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:44 #, python-format msgid "%3d URL" msgid_plural "%3d URLs" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:46 #, python-format msgid "runtime %s" msgstr "tiempo de corrida %s" #: ../linkcheck/director/console.py:66 #, fuzzy, python-format msgid "" "********** Oops, I did it again. *************\n" "\n" "You have found an internal error in LinkChecker. Please write a bug report\n" "at %s\n" "and include the following information:\n" "- the URL or file you are testing\n" "- the system information below\n" "\n" "When using the commandline client:\n" "- your commandline arguments and any custom configuration files.\n" "- the output of a debug run with option \"-Dall\"\n" "\n" "Not disclosing some of the information above due to privacy reasons is ok.\n" "I will try to help you nonetheless, but you have to give me something\n" "I can work with ;) .\n" msgstr "" "********** Oh, lo hice otra vez. *************\n" "\n" "Usted ha encontrado un error interno en LinkChecker. Por favor escriba\n" "un reporte de error en http://sourceforge.net/tracker/?" "func=add&group_id=1913&atid=101913\n" "o escriba un correo-e a %s e incluya la información siguiente:\n" "- el URL o archivo que usted está probando,\n" "- sus argumentos de la línea de comandos y/o configuración,\n" "- la salida de una corrida de depuración del comando ejecutado con la\n" " opción \"-Dall\", y\n" "- la información del sistema debajo.\n" "\n" "Está bien no revelar alguna de la información arriba debido a razones\n" "de privacidad. Intentaré ayudarle de todos modos, pero debe darme algo\n" "con que pueda trabajar ;) .\n" #: ../linkcheck/director/console.py:94 #, fuzzy msgid "******** LinkChecker internal error, over and out ********" msgstr "******** Error interno de LinkChecker, saliéndose ********" #: ../linkcheck/director/console.py:140 msgid "System info:" msgstr "Información del sistema:" #: ../linkcheck/director/console.py:142 msgid "Released on:" msgstr "" #: ../linkcheck/director/console.py:144 ../linkcheck/command/linkchecker.py:130 #, python-format msgid "Python %(version)s on %(platform)s" msgstr "Pitón %(version)s en %(platform)s" #: ../linkcheck/director/console.py:152 #, fuzzy msgid "Local time:" msgstr "Tiempo de bajada" #: ../linkcheck/director/console.py:153 msgid "sys.argv:" msgstr "" #: ../linkcheck/director/console.py:158 msgid "released" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:56 #, fuzzy msgid "HTML syntax check plugin is broken. Fixes welcome." msgstr "Error de sintaxis en %(arg)r: %(msg)s" #: ../linkcheck/plugins/syntaxchecks.py:74 msgid "valid HTML syntax" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:81 #, fuzzy, python-format msgid "HTML syntax check plugin error: %(msg)s " msgstr "Error de sintaxis en %(arg)r: %(msg)s" #: ../linkcheck/plugins/syntaxchecks.py:114 msgid "valid CSS syntax" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:121 #, fuzzy, python-format msgid "CSS syntax check plugin error: %(msg)s " msgstr "Error de sintaxis en %(arg)r: %(msg)s" #: ../linkcheck/plugins/syntaxchecks.py:132 #, python-format msgid "%(w3type)s validation error at line %(line)s col %(column)s: %(msg)s" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:136 #, python-format msgid "%(w3type)s validation error at line %(line)s: %(msg)s" msgstr "" #: ../linkcheck/plugins/markdowncheck.py:88 #: ../linkcheck/plugins/regexcheck.py:45 #, python-format msgid "Invalid regex pattern %r: %s" msgstr "" #: ../linkcheck/plugins/regexcheck.py:61 #, fuzzy, python-format msgid "Found %(match)r at line %(line)d in link contents." msgstr "Se encontró %(match)r en los contenidos del enlace." #: ../linkcheck/plugins/sslcertcheck.py:70 msgid "certificate did not include \"notAfter\" information" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:73 msgid "SSL verification is disabled; enable the sslverify option" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:85 #, python-format msgid "Invalid SSL certificate \"notAfter\" value %r" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:94 #, python-format msgid "SSL certificate is expired on %(expire)s." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:100 #, python-format msgid "SSL certificate expires on %(expire)s and is only %(valid)s valid." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:104 #, python-format msgid "SSL certificate expires on %(expire)s and is %(valid)s valid." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:118 #: ../linkcheck/configuration/confparse.py:98 #: ../linkcheck/configuration/confparse.py:116 #, python-format msgid "invalid value for %s: %d must not be less than %d" msgstr "" #: ../linkcheck/plugins/locationinfo.py:46 #, fuzzy, python-format msgid "URL is located in %(location)s." msgstr "El URL está localizado en %(country)s." #: ../linkcheck/plugins/viruscheck.py:101 msgid "clamd is not ready for stream scanning" msgstr "" #: ../linkcheck/plugins/viruscheck.py:160 msgid "ScannerDaemonOutputFormat must be disabled" msgstr "" #: ../linkcheck/plugins/viruscheck.py:163 msgid "only one of TCPSocket and LocalSocket must be enabled" msgstr "" #: ../linkcheck/plugins/viruscheck.py:193 msgid "one of TCPSocket or LocalSocket must be enabled" msgstr "" #: ../linkcheck/plugins/viruscheck.py:229 #, fuzzy msgid "Could not connect to ClamAV daemon." msgstr "No pude conectar, pero la sintaxis es correcta" #: ../linkcheck/plugins/anchorcheck.py:70 #, fuzzy, python-format msgid "Anchor `%(name)s' (decoded: `%(decoded)s') not found." msgstr "No se encontró el ancla `%(name)s'." #: ../linkcheck/plugins/anchorcheck.py:71 #, python-format msgid "Available anchors: %(anchors)s." msgstr "" #: ../linkcheck/cookies.py:46 #, fuzzy msgid "No entries found" msgstr "No se especificó un servidor NNTP, pasando por alto este URL." #: ../linkcheck/cmdline.py:61 #, python-format msgid "Error: %(msg)s" msgstr "Error: %(msg)s" #: ../linkcheck/cmdline.py:63 #, fuzzy, python-format msgid "Execute '%(program)s -h' for help" msgstr "Ejecute 'linkchecker -h' para obtener ayuda" #: ../linkcheck/configuration/__init__.py:227 #, python-format msgid "Configuration file %r does not exist." msgstr "" #: ../linkcheck/configuration/__init__.py:229 #, python-format msgid "Configuration file %r is not readable." msgstr "" #: ../linkcheck/configuration/__init__.py:239 msgid "missing user or URL pattern in authentication data." msgstr "" #: ../linkcheck/configuration/__init__.py:274 msgid "activating text logger output." msgstr "" #: ../linkcheck/configuration/__init__.py:285 msgid "no user/password authentication data found for login URL." msgstr "" #: ../linkcheck/configuration/__init__.py:289 msgid "login URL is not a HTTP URL." msgstr "" #: ../linkcheck/configuration/__init__.py:293 msgid "login URL is incomplete." msgstr "" #: ../linkcheck/configuration/__init__.py:296 #, python-format msgid "disabling login URL %(url)s." msgstr "" #: ../linkcheck/configuration/__init__.py:349 #, python-format msgid "could not create plugin directory %(dirname)r: %(errmsg)r" msgstr "" #: ../linkcheck/configuration/__init__.py:397 #, python-format msgid "" "could not copy initial configuration file %(src)r to %(dst)r: %(errmsg)r" msgstr "" #: ../linkcheck/configuration/confparse.py:62 #, python-format msgid "configuration files %s contain no sections." msgstr "" #: ../linkcheck/configuration/confparse.py:75 #, python-format msgid "Error parsing configuration: %s" msgstr "" #: ../linkcheck/configuration/confparse.py:83 #, python-format msgid "invalid empty value for %s: %s\n" msgstr "" #: ../linkcheck/configuration/confparse.py:103 #: ../linkcheck/configuration/confparse.py:121 #, python-format msgid "invalid value for %s: %d must not be greater than %d" msgstr "" #: ../linkcheck/configuration/confparse.py:136 msgid "" "The blacklist section in linkcheckerrc is deprecated, please rename to " "failures" msgstr "" #: ../linkcheck/configuration/confparse.py:237 #, python-format msgid "missing auth part in entry %(val)r" msgstr "" #: ../linkcheck/configuration/confparse.py:247 #, python-format msgid "invalid login URL `%s'. Only HTTP and HTTPS URLs are supported." msgstr "" #: ../linkcheck/configuration/confparse.py:276 #, python-format msgid "" "The configuration file %s contains password information (in section [%s] and " "options %s) and the file is readable by others. Please make the file only " "readable by you." msgstr "" #: ../linkcheck/configuration/confparse.py:285 #, python-format msgid "For example execute 'chmod go-rw %s'." msgstr "" #: ../linkcheck/configuration/confparse.py:290 #, python-format msgid "See %(url)s for more info on setting file permissions." msgstr "" #: ../linkcheck/lc_cgi.py:215 #, fuzzy, python-format msgid "could not set locale %r: %s" msgstr "no se pudo analizar el contenido: %(msg)r" #: ../linkcheck/lc_cgi.py:217 #, fuzzy, python-format msgid "unsupported language %r" msgstr "lenguaje sin soporte" #: ../linkcheck/lc_cgi.py:222 msgid "empty url was given" msgstr "se dió un URL vacío" #: ../linkcheck/lc_cgi.py:224 #, fuzzy, python-format msgid "disallowed url %r was given" msgstr "se dió un URL no permitido" #: ../linkcheck/lc_cgi.py:226 msgid "no url was given" msgstr "no se dió un URL" #: ../linkcheck/lc_cgi.py:231 #, fuzzy, python-format msgid "invalid recursion level %r" msgstr "nivel de recursión inválido" #: ../linkcheck/lc_cgi.py:237 #, fuzzy, python-format msgid "invalid %s option %r" msgstr "opción de registro %r inválida" #: ../linkcheck/lc_cgi.py:264 #, fuzzy, python-format msgid "" "\n" "\n" "\n" "LinkChecker Online Error\n" "\n" "
\n" "Error: %s
\n" "The LinkChecker Online script has encountered an error. Please ensure\n" "that your provided URL link begins with http:// and\n" "contains only these characters: A-Za-z0-9./_~-

\n" "Errors are logged.\n" "
\n" "\n" "" msgstr "" "\n" "Error de LinkChecker en línea\n" "\n" "
\n" "Error: %s
\n" "El guión LinkChecker En línea ha encontrado un error. Por favor asegúrese\n" "que en enlcade del URL proveído comience con http:// y " "contenga\n" "sólo estos caracteres: A-Za-z0-9./_~-

\n" "Los errores son registrados.\n" "
\n" "\n" "" #: ../linkcheck/checker/fileurl.py:142 #, fuzzy, python-format msgid "Could not get current working directory: %(msg)s" msgstr "no se pudo analizar el contenido: %(msg)r" #: ../linkcheck/checker/fileurl.py:175 ../linkcheck/checker/fileurl.py:339 #, fuzzy msgid "Added trailing slash to directory." msgstr "Se adicionó \"slash\" final al directorio." #: ../linkcheck/checker/fileurl.py:198 ../linkcheck/checker/fileurl.py:352 msgid "" "local files are only checked without parent URL or when the parent URL is " "also a file" msgstr "" #: ../linkcheck/checker/fileurl.py:203 ../linkcheck/checker/fileurl.py:367 msgid "directory" msgstr "directorio" #: ../linkcheck/checker/fileurl.py:222 #, python-format msgid "" "The URL path %(path)r is not the same as the system path %(realpath)r. You " "should always use the system path in URLs." msgstr "" "El camino %(path)r del URL no es el mismo que el camino %(realpath)r del " "sistema.\n" "Debería usar siempre el camino del sistema en los URLs." #: ../linkcheck/checker/fileurl.py:360 #, python-format msgid "" "URL `%s' is a directory with an anchor. When checking local files " "AnchorCheck does not support anchors for directories." msgstr "" #: ../linkcheck/checker/itmsservicesurl.py:31 msgid "Missing required url parameter" msgstr "" #: ../linkcheck/checker/urlbase.py:79 #, python-format msgid "URL has unparsable domain name: %(name)s" msgstr "" #: ../linkcheck/checker/urlbase.py:163 #, fuzzy msgid "The URL is outside of the domain filter, checked only syntax." msgstr "Fuera del filtro de dominio, se chequeó sólo la sintaxis." #: ../linkcheck/checker/urlbase.py:166 msgid "filtered" msgstr "" #: ../linkcheck/checker/urlbase.py:216 #, python-format msgid "Leading or trailing whitespace in URL `%(url)s'." msgstr "" #: ../linkcheck/checker/urlbase.py:340 #, python-format msgid "The URL with content type %r is not parseable." msgstr "" #: ../linkcheck/checker/urlbase.py:445 msgid "URL is empty" msgstr "El URL está vacío" #: ../linkcheck/checker/urlbase.py:460 #, python-format msgid "Effective URL %(url)r." msgstr "URL efectivo %(url)r." #: ../linkcheck/checker/urlbase.py:467 #, fuzzy, python-format msgid "URL length %(len)d is longer than %(max)d." msgstr "El tamaño del contenido %(dlsize)s es más grande que %(maxbytes)s." #: ../linkcheck/checker/urlbase.py:517 ../linkcheck/checker/urlbase.py:523 #, fuzzy, python-format msgid "URL host %(host)r has invalid port" msgstr "El URL tiene un puerto %(port)r inválido" #: ../linkcheck/checker/urlbase.py:530 #, fuzzy msgid "URL has empty hostname" msgstr "El URL está vacío" #: ../linkcheck/checker/urlbase.py:555 #, python-format msgid "URL %(url)s has obfuscated IP address %(ip)s" msgstr "" #: ../linkcheck/checker/urlbase.py:591 msgid "Hostname not found" msgstr "No se encontró el nombre del servidor" #: ../linkcheck/checker/urlbase.py:594 #, python-format msgid "Bad hostname %(host)r: %(msg)s" msgstr "" #: ../linkcheck/checker/urlbase.py:614 #, fuzzy, python-format msgid "could not get content: %(msg)s" msgstr "no se pudo analizar el contenido: %(msg)r" #: ../linkcheck/checker/urlbase.py:669 #, fuzzy, python-format msgid "Content size %(size)s is larger than %(maxbytes)s." msgstr "El tamaño del contenido %(dlsize)s es más grande que %(maxbytes)s." #: ../linkcheck/checker/urlbase.py:763 msgid "Content size is zero." msgstr "" #: ../linkcheck/checker/urlbase.py:800 ../linkcheck/checker/httpurl.py:348 msgid "File size too large" msgstr "" #: ../linkcheck/checker/urlbase.py:881 #, python-format msgid "URL has unparsable domain name: %(domain)s" msgstr "" #: ../linkcheck/checker/unknownurl.py:32 #, python-format msgid "%(scheme)s URL ignored." msgstr "URL %(scheme)s ignorado." #: ../linkcheck/checker/unknownurl.py:34 #, fuzzy msgid "ignored" msgstr "URL %s ignorado." #: ../linkcheck/checker/unknownurl.py:36 msgid "URL is unrecognized or has invalid syntax" msgstr "No se reconoce el URL o tiene sintaxis inválida" #: ../linkcheck/checker/mailtourl.py:88 #, fuzzy, python-format msgid "No mail addresses or email subject found in `%(url)s'." msgstr "No se encontraron direcciones." #: ../linkcheck/checker/mailtourl.py:132 #, python-format msgid "Error parsing CGI values: %s" msgstr "" #: ../linkcheck/checker/mailtourl.py:158 #, python-format msgid "" "Mail address `%(addr)s' too long. Allowed 256 chars, was %(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:168 #, python-format msgid "Missing `@' in mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:177 #, python-format msgid "Missing local part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:184 #, python-format msgid "Missing domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:192 #, python-format msgid "" "Local part of mail address `%(addr)s' too long. Allowed 64 chars, was " "%(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:203 #, python-format msgid "" "Domain part of mail address `%(addr)s' too long. Allowed 255 chars, was " "%(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:218 #, python-format msgid "Unquoted double quote or backslash in mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:227 #, python-format msgid "Local part of mail address `%(addr)s' may not start with a dot." msgstr "" #: ../linkcheck/checker/mailtourl.py:235 #, python-format msgid "Local part of mail address `%(addr)s' may not end with a dot." msgstr "" #: ../linkcheck/checker/mailtourl.py:243 #, python-format msgid "Local part of mail address `%(addr)s' may not contain two dots." msgstr "" #: ../linkcheck/checker/mailtourl.py:253 #, python-format msgid "" "Local part of mail address `%(addr)s' contains unquoted character `%(char)s." msgstr "" #: ../linkcheck/checker/mailtourl.py:271 #, python-format msgid "Domain part of mail address `%(addr)s' has invalid IP." msgstr "" #: ../linkcheck/checker/mailtourl.py:281 #, python-format msgid "Invalid domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:289 #, python-format msgid "Invalid top level domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:327 #, python-format msgid "No MX mail host for %(domain)s found." msgstr "No se encontró servidor MX para %(domain)s." #: ../linkcheck/checker/mailtourl.py:336 #, fuzzy, python-format msgid "No host for %(domain)s found." msgstr "No se encontró servidor MX para %(domain)s." #: ../linkcheck/checker/mailtourl.py:353 #, python-format msgid "Got invalid DNS answer %(answer)s for %(domain)s." msgstr "" #: ../linkcheck/checker/mailtourl.py:366 #, fuzzy msgid "Valid mail address syntax" msgstr "Sintaxis de correo inválida" #: ../linkcheck/checker/const.py:99 msgid "The effective URL is different from the original." msgstr "" #: ../linkcheck/checker/const.py:100 msgid "Could not get the content of the URL." msgstr "" #: ../linkcheck/checker/const.py:101 msgid "The URL content size is too large." msgstr "" #: ../linkcheck/checker/const.py:102 msgid "The URL content size is zero." msgstr "" #: ../linkcheck/checker/const.py:103 msgid "The URL content type is not parseable." msgstr "" #: ../linkcheck/checker/const.py:104 msgid "The URL is longer than the recommended size." msgstr "" #: ../linkcheck/checker/const.py:105 msgid "The URL contains leading or trailing whitespace." msgstr "" #: ../linkcheck/checker/const.py:106 msgid "The file: URL is missing a trailing slash." msgstr "" #: ../linkcheck/checker/const.py:108 msgid "The file: path is not the same as the system specific path." msgstr "" #: ../linkcheck/checker/const.py:111 msgid "A local directory with an anchor, not supported by AnchorCheck." msgstr "" #: ../linkcheck/checker/const.py:112 msgid "The ftp: URL is missing a trailing slash." msgstr "" #: ../linkcheck/checker/const.py:113 msgid "The URL had no content." msgstr "" #: ../linkcheck/checker/const.py:114 msgid "An error occurred while storing a cookie." msgstr "" #: ../linkcheck/checker/const.py:115 msgid "The URL request was rate limited." msgstr "" #: ../linkcheck/checker/const.py:116 msgid "Redirected to a different URL." msgstr "" #: ../linkcheck/checker/const.py:117 msgid "The mail MX host could not be found." msgstr "" #: ../linkcheck/checker/const.py:118 msgid "The IP is obfuscated." msgstr "" #: ../linkcheck/checker/const.py:119 msgid "XML could not be parsed." msgstr "" #: ../linkcheck/checker/ftpurl.py:75 msgid "Got no answer from FTP server" msgstr "No se obtuvo respuesta del servidor FTP" #: ../linkcheck/checker/ftpurl.py:78 #, python-format msgid "Remote host has closed connection: %(msg)s" msgstr "El servidor remoto ha cerrado la conexión: %(msg)s" #: ../linkcheck/checker/ftpurl.py:124 msgid "Missing trailing directory slash in ftp url." msgstr "Falta el \"slash\" final en el URL de FTP." #: ../linkcheck/checker/ftpurl.py:188 msgid "FTP file size too large" msgstr "" #: ../linkcheck/checker/httpurl.py:138 #, fuzzy msgid "Access denied by robots.txt, checked only syntax." msgstr "Denegado el acceso por robots.txt, chequeando sólo la sintaxis." #: ../linkcheck/checker/httpurl.py:139 msgid "syntax OK" msgstr "" #: ../linkcheck/checker/httpurl.py:283 #, fuzzy, python-format msgid "Redirected to `%(url)s' status: %(code)d %(reason)s." msgstr "Redireccionado a `%(url)s'." #: ../linkcheck/checker/httpurl.py:336 msgid "OK" msgstr "" #: ../linkcheck/checker/dnsurl.py:46 #, python-format msgid "%(host)s resolved to IPs %(ips)s" msgstr "" #: ../linkcheck/checker/dnsurl.py:48 #, python-format msgid "%(host)r could not be resolved" msgstr "" #: ../linkcheck/command/setup_config.py:49 msgid "Running with python -O disables debugging." msgstr "" #: ../linkcheck/command/setup_config.py:81 #, python-format msgid "blacklist is deprecated for option %(option)s, using failures instead" msgstr "" #: ../linkcheck/command/setup_config.py:87 #: ../linkcheck/command/setup_config.py:133 #, fuzzy, python-format msgid "Unknown logger type %(type)r in %(output)r for option %(option)s" msgstr "Tipo %r de registrador desconocido en %r para la opción %s" #: ../linkcheck/command/setup_config.py:94 #: ../linkcheck/command/setup_config.py:144 #, fuzzy, python-format msgid "Unknown encoding %(encoding)r in %(output)r for option %(option)s" msgstr "Codificación %r desconocida en %r para la opción %s" #: ../linkcheck/command/setup_config.py:127 #, python-format msgid "" "blacklist logger is deprecated for option %(option)s, using failures instead" msgstr "" #: ../linkcheck/command/setup_config.py:159 #, python-format msgid "Enter LinkChecker HTTP/FTP password for user %(user)s:" msgstr "" #: ../linkcheck/command/setup_config.py:163 msgid "Enter LinkChecker HTTP/FTP password:" msgstr "" #: ../linkcheck/command/setup_config.py:181 #, python-format msgid "Illegal argument %(arg)r for option %(option)s" msgstr "Argumento ilegal %(arg)r para la opción %(option)s" #: ../linkcheck/command/setup_config.py:198 #, python-format msgid "Enter LinkChecker password for user %(user)s at %(strpattern)s:" msgstr "" #: ../linkcheck/command/setup_config.py:207 #, python-format msgid "Cookie file %s does not exist." msgstr "" #: ../linkcheck/command/setup_config.py:210 #, fuzzy, python-format msgid "Could not read cookie file %s" msgstr "No se pudieron almacenar las \"cookies\": %s." #: ../linkcheck/command/linkchecker.py:50 msgid "Running as root user; dropping privileges by changing user to nobody." msgstr "" #: ../linkcheck/command/linkchecker.py:124 #, python-format msgid "Invalid debug level %(level)r" msgstr "Nivel de depuración inválido %(level)r" #: ../linkcheck/command/linkchecker.py:140 #, python-format msgid "Config file %s does not exist." msgstr "" #: ../linkcheck/command/linkchecker.py:143 #, fuzzy, python-format msgid "Could not read config file %s." msgstr "No se pudieron almacenar las \"cookies\": %s." #: ../linkcheck/command/linkchecker.py:176 msgid "no files or URLs given" msgstr "no se han dado archivos o URLs" #: ../linkcheck/command/linkchecker.py:184 #, python-format msgid "" "Overwrite profiling file %(file)r?\n" "Press Ctrl-C to cancel, RETURN to continue." msgstr "" "¿Sobreescribir archivo %(file)r de perfilamiento?\n" "Presione Ctrl-C para cancelar, RETORNO para continuar." #: ../linkcheck/command/linkchecker.py:192 msgid "Canceled." msgstr "Cancelado." #: ../linkcheck/command/linkchecker.py:199 #, fuzzy msgid "" "The `yappi' Python module is not installed, therefore the --profile option " "is disabled." msgstr "" "El módulo `profile' de Python no está instalado, por tanto la opción --" "profile está deshabilitada." #: ../linkcheck/command/linkchecker.py:218 msgid "Dumping memory statistics..." msgstr "" #: ../linkcheck/command/linkchecker.py:220 #, python-format msgid "The memory dump has been written to `%(filename)s'." msgstr "" #: ../linkcheck/command/arg_parser.py:28 #, fuzzy msgid "" "NOTES\n" " o URLs on the command line starting with \"ftp.\" are treated like\n" " \"ftp://ftp.\", URLs starting with \"www.\" are treated like \"http://www." "\".\n" " You can also give local files as arguments.\n" " o If you have your system configured to automatically establish a\n" " connection to the internet (e.g. with diald), it will connect when\n" " checking links not pointing to your local system.\n" " See the --ignore-url option on how to prevent this.\n" " o Javascript links are currently ignored.\n" " o If your platform does not support threading, LinkChecker disables it\n" " automatically.\n" " o You can supply multiple user/password pairs in a configuration file.\n" msgstr "" "NOTAS\n" "o Un ! antes de una expresión regular la niega. Así '!^mailto:' coincide\n" " con todo menos un enlace 'mailto'.\n" "o Los URLs de la línea de comandos comenzando con \"ftp.\" son tratados\n" " como \"ftp://ftp.\", los URLs comenzando con \"www.\" son tratados como\n" " \"http://www.\".\n" " También puede dar archivos locales como argumentos.\n" "o Si tiene su sistema configurado para establecer automáticamente una\n" " conexión a internet (ej.: con diald), se conectará cuando se chequeen\n" " enlaces que no apunten a sus sistema local.\n" " Vea la opción --extern-strict-all para ver como prevernir esto.\n" "o Los enlaces de Javascript se ignoran en este momento.\n" "o Si su plataforma no soporta hilos, LinkChecker los deshabilita\n" " automáticamente.\n" "o Puede suplir varios pares de usuario/contraseña en un archivo de\n" " configuración\n" "\n" "o Para usar proxies asigne un valor a las variables $http_proxy,\n" " $https_proxy, $ftp_proxy, en Unix o Windows.\n" " En Mac use la Configuración de Internet.\n" "o ¡Cuando se chequean los enlaces 'news:' el servidor NTTP no necesita ser\n" " el mismo que el servidor del usuario navegando sus páginas!\n" #: ../linkcheck/command/arg_parser.py:44 msgid "" "PROXY SUPPORT\n" "To use a proxy on Unix or Windows set $http_proxy or $https_proxy\n" "to the proxy URL. The URL should be of the form\n" "\"http://[:@][:]\".\n" "LinkChecker also detects manual proxy settings of Internet Explorer under\n" "Windows systems. On a Mac use the Internet Config to select a proxy.\n" "\n" "LinkChecker honors the $no_proxy environment variable. It can be a list\n" "of domain names for which no proxy will be used.\n" "\n" "Setting a HTTP proxy on Unix for example looks like this:\n" "\n" " export http_proxy=\"http://proxy.example.com:8080\"\n" "\n" "Proxy authentication is also supported:\n" "\n" " export http_proxy=\"http://user1:mypass@proxy.example.org:8081\"\n" "\n" "Setting a proxy on the Windows command prompt:\n" "\n" " set http_proxy=http://proxy.example.com:8080\n" "\n" msgstr "" #: ../linkcheck/command/arg_parser.py:70 msgid "" "REGULAR EXPRESSIONS\n" "Only Python regular expressions are accepted by LinkChecker.\n" "See https://docs.python.org/howto/regex.html for an introduction in\n" "regular expressions.\n" "\n" "The only addition is that a leading exclamation mark negates\n" "the regular expression.\n" msgstr "" #: ../linkcheck/command/arg_parser.py:81 msgid "" "COOKIE FILES\n" "A cookie file contains standard RFC 805 header data with the following\n" "possible names:\n" "Scheme (optional)\n" " Sets the scheme the cookies are valid for; default scheme is 'http'.\n" "Host (required)\n" " Sets the domain the cookies are valid for.\n" "Path (optional)\n" " Gives the path the cookies are value for; default path is '/'.\n" "Set-cookie (optional)\n" " Set cookie name/value. Can be given more than once.\n" "\n" "Multiple entries are separated by a blank line.\n" "\n" "The example below will send two cookies to all URLs starting with\n" "'http://example.org/hello/' and one to all URLs starting\n" "with 'https://example.com/':\n" "\n" "Host: example.org\n" "Path: /hello\n" "Set-cookie: ID=\"smee\"\n" "Set-cookie: spam=\"egg\"\n" "\n" "Scheme: https\n" "Host: example.com\n" "Set-cookie: baggage=\"elitist\"; comment=\"hologram\"\n" msgstr "" #: ../linkcheck/command/arg_parser.py:111 #, fuzzy msgid "" "RETURN VALUE\n" "The return value is non-zero when\n" " o invalid links were found or\n" " o warnings were found warnings are enabled\n" " o a program error occurred\n" msgstr "" "VALOR RETORNADO\n" "El valor retornado es diferente de cero cuando:\n" " o se encontraron enlaces inválidos, o\n" " o se encontraron advertencias de enlace link warnings y se dió la opción\n" " --warnings\n" " o ocurrió un error del programa\n" #: ../linkcheck/command/arg_parser.py:120 #, fuzzy msgid "" "EXAMPLES\n" "The most common use checks the given domain recursively, plus any\n" "single URL pointing outside of the domain:\n" " linkchecker http://www.example.org/\n" "Beware that this checks the whole site which can have several hundred\n" "thousands URLs. Use the -r option to restrict the recursion depth.\n" "\n" "Don't connect to mailto: hosts, only check their URL syntax. All other\n" "links are checked as usual:\n" " linkchecker --ignore-url=^mailto: www.example.org\n" "\n" "Checking local HTML files on Unix:\n" " linkchecker ../bla.html subdir/blubber.html\n" "\n" "Checking a local HTML file on Windows:\n" " linkchecker c:\\temp\\test.html\n" "\n" "You can skip the \"http://\" url part if the domain starts with \"www.\":\n" " linkchecker www.example.de\n" "\n" "You can skip the \"ftp://\" url part if the domain starts with \"ftp.\":\n" " linkchecker -r0 ftp.example.org\n" msgstr "" "EJEMPLOS\n" "El uso más común chequea el dominio dado recursivamente, además de\n" "cualquier URL simple apuntando afuera del dominio:\n" " linkchecker http://tesoro.liborio.int/\n" "Tenga en cuanta que esto chequea el sitio completo, el cual puede\n" "tener varios cientos de miles de URLs. Use la opción -r para\n" "restringir la profundidad de la recursión.\n" "\n" "No conectarse a anfitriones mailto:, sólo chequear su sintaxis\n" "URL. Todos los demás enlaces son chequeados como usual:\n" " linkchecker --intern='!^mailto:' --extern-strict-all www.misitio.org\n" "\n" "Chequeando un archivo HTML local en Unix:\n" " linkchecker ../bla.html\n" "\n" "Chequeando un archivo HTML local en Windows:\n" " linkchecker c:\\temp\\test.html\n" "\n" "Puede saltarse la parte del URL \"http://\" si el dominio comienza con\n" "\"www.\":\n" " linkchecker www.mipagina.int\n" "\n" "Puede saltarse la parte del URL \"ftp://\" si el dominio comienza con\n" "\"ftp.\":\n" " linkchecker -r0 ftp.linux.org\n" #: ../linkcheck/command/arg_parser.py:146 #, fuzzy msgid "" "OUTPUT TYPES\n" "Note that by default only errors and warnings are logged.\n" "You should use the --verbose option to see valid URLs,\n" "and when outputting a sitemap graph format.\n" "\n" "text Standard text output, logging URLs in keyword: argument fashion.\n" "html Log URLs in keyword: argument fashion, formatted as HTML.\n" " Additionally has links to the referenced pages. Invalid URLs have\n" " HTML and CSS syntax check links appended.\n" "csv Log check result in CSV format with one URL per line.\n" "gml Log parent-child relations between linked URLs as a GML sitemap\n" " graph.\n" "dot Log parent-child relations between linked URLs as a DOT sitemap\n" " graph.\n" "gxml Log check result as a GraphXML sitemap graph.\n" "xml Log check result as machine-readable XML.\n" "sql Log check result as SQL script with INSERT commands. An example\n" " script to create the initial SQL table is included as create.sql.\n" "failures\n" " Suitable for cron jobs. Logs the check result into a file\n" " $XDG_DATA_HOME/linkchecker/failures which only contains entries " "with\n" " invalid URLs and the number of times they have failed.\n" "none Logs nothing. Suitable for debugging or checking the exit code.\n" msgstr "" "TIPOS DE SALIDA\n" "Note que por omisión sólo se registran los errores.\n" "\n" "text Salido estándar de texto, registrando los URLs en la forma llave: " "argumento.\n" "html Registra los URLs en la forma llave: argumento, formateado como " "HTML.\n" " Adicionalmente tiene enlaces a las páginas referenciadas. Los URLs " "inválidos\n" " adicionados enlaces de chequeo de HTML y CSS.\n" "csv Registra el resultado del chequeo en formato CSV con un URL por " "línea.\n" "gml Registra relaciones padre-hijo entre URLs enlazados como un grafo " "GML.\n" " Debería usar la opción --verbose para obtener un grafo completo.\n" "dot Registra relaciones padre-hijo entre URLs enlazados como un grafo " "DOT.\n" " Debería usar la opción --verbose para obtener un grafo completo.\n" "xml Registra el resultado del chequeo como un archivo XML leíble por la " "máquina.\n" "sql Registra el resultado del chequeo como un guión SQL con\n" " comandos INSERT. Un guión de ejemplo para crear la tabla SQL\n" " inicial se incluye como create.sql.\n" "blacklist\n" " Apropiado para los trabajos de cron. Registra el resultado del\n" " chequeo en un archivo ~/.linkchecker/blacklist el cual sólo\n" " contiene entradas con URLs inválidos y la cantidad de veces\n" " que han fallado.\n" "\n" "none No registra nada. Apropiado para guiones.\n" #: ../linkcheck/command/arg_parser.py:174 msgid "" "IGNORE WARNINGS\n" "The following warnings are recognized in the 'ignorewarnings' config\n" "file entry:\n" msgstr "" #: ../linkcheck/command/arg_parser.py:212 msgid "General options" msgstr "Opciones generales" #: ../linkcheck/command/arg_parser.py:219 #, fuzzy, python-format msgid "" "Use FILENAME as configuration file. Per default LinkChecker uses\n" "$XDG_CONFIG_HOME/linkchecker/linkcheckerrc (under Windows\n" "%%HOMEPATH%%\\.config\\linkchecker\\linkcheckerrc)." msgstr "" "Use CONFIGFILE como archivo de configuración. Por omisión LinkChecker\n" "primero busca /etc/linkchecker/linkcheckerrc y entonces\n" "~/.linkchecker/linkcheckerrc (en Windows\n" "\\linkcheckerrc)." #: ../linkcheck/command/arg_parser.py:230 #, fuzzy msgid "" "Generate no more than the given number of threads. Default number\n" "of threads is 10. To disable threading specify a non-positive number." msgstr "No generar mas de num de hilos. Por omisión el número de hilos es 10." #: ../linkcheck/command/arg_parser.py:235 msgid "Print version and exit." msgstr "Imprimir versión y salir." #: ../linkcheck/command/arg_parser.py:241 #, fuzzy msgid "Print available check plugins and exit." msgstr "Imprimir versión y salir." #: ../linkcheck/command/arg_parser.py:246 msgid "Read list of white-space separated URLs to check from stdin." msgstr "" #: ../linkcheck/command/arg_parser.py:250 msgid "Output options" msgstr "Opciones de salida" #: ../linkcheck/command/arg_parser.py:257 #, fuzzy, python-format msgid "" "Print debugging output for the given logger.\n" "Available loggers are %(lognamelist)s.\n" "Specifying 'all' is an alias for specifying all available loggers.\n" "The option can be given multiple times to debug with more\n" "than one logger.\n" "\n" "For accurate results, threading will be disabled during debug runs." msgstr "" "Imprimir salida de depuración para el registrador dado.\n" "Los registradores disponibles son %(lognamelist)s.\n" "Especificando 'all' es un alias para especificar todos los registradores\n" "disponibles.\n" "La opción puede darse varias veces para depurar con más de un registrador.\n" "\n" "Para resultados acertados, se desahabilitará el uso de hilos durante\n" "las corridas de depuración." #: ../linkcheck/command/arg_parser.py:274 #, fuzzy, python-format msgid "" "Output to a file linkchecker-out.TYPE, $XDG_DATA_HOME/linkchecker/failures " "for\n" "'failures' output, or FILENAME if specified.\n" "The ENCODING specifies the output encoding, the default is that of your\n" "locale.\n" "Valid encodings are listed at https://docs.python.org/library/codecs." "html#standard-encodings.\n" "The FILENAME and ENCODING parts of the 'none' output type will be ignored,\n" "else if the file already exists, it will be overwritten.\n" "You can specify this option more than once. Valid file output types\n" "are %(loggertypes)s. You can specify this option multiple times to output\n" "to more than one file. Default is no file output. Note that you can\n" "suppress all console output with the option '-o none'." msgstr "" "Salida hacia un archivo linkchecker-out.TYPE,\n" "$HOME/.linkchecker/blacklist para la salida 'blacklist', o\n" "NOMBREDEARCHIVO si se especifica.\n" "CODIFICACIÓN especifica la codificación de la salida, si se omite es\n" "\"iso-8859-1\".\n" "Las codificaciones válidas están listadas en\n" "http://docs.python.org/lib/node127.html.\n" "Las partes NOMBREDEARCHIVO y CODIFICACIÓN del tipo de salida 'none'\n" "serán ignoradas, si no, si el archivo ya existe, será sobreescrito.\n" "Puede especificar esta opción más de una vez. TIPOs de archivos de\n" "salida válidos son %(loggertypes)s. Puede especificar esta opción varias\n" "veces para sacar más de un archivo. Por omisión es no sacar hacia\n" "archivo. Note que puede suprimir toda salida hacia la consola con la\n" "opción '-o none'." #: ../linkcheck/command/arg_parser.py:294 msgid "Do not print check status messages." msgstr "No imprimir mensajes de estado del chequeo." #: ../linkcheck/command/arg_parser.py:300 msgid "Don't log warnings. Default is to log warnings." msgstr "" #: ../linkcheck/command/arg_parser.py:308 #, fuzzy, python-format msgid "" "Specify output as %(loggertypes)s. Default output type is text.\n" "The ENCODING specifies the output encoding, the default is that of your\n" "locale.\n" "Valid encodings are listed at https://docs.python.org/library/codecs." "html#standard-encodings." msgstr "" "Especificar la salida como %(loggertypes)s. El tipo de salida por\n" "omisión es texto. ENCODING especifica la codificación de la salida,\n" "por omisión es \"iso-8859-1\". Las codificaciones válidas están listadas\n" "en http://docs.python.org/lib/node127.html." #: ../linkcheck/command/arg_parser.py:325 #, fuzzy msgid "" "Quiet operation, an alias for '-o none'.\n" "This is only useful with -F." msgstr "Operación callada. Esta es sólo útil con -F." #: ../linkcheck/command/arg_parser.py:336 #, fuzzy msgid "Log all URLs. Default is to log only errors and warnings." msgstr "" "Registra todos los URLs chequeados (implica -w). Por omisión se\n" "registran sólo los URLs inválidos." #: ../linkcheck/command/arg_parser.py:340 msgid "Checking options" msgstr "Opciones de chequeo" #: ../linkcheck/command/arg_parser.py:346 msgid "" "Read a file with initial cookie data. The cookie data format is\n" "explained below." msgstr "" #: ../linkcheck/command/arg_parser.py:356 msgid "Disable robots.txt checks" msgstr "" #: ../linkcheck/command/arg_parser.py:362 msgid "Check external URLs." msgstr "" #: ../linkcheck/command/arg_parser.py:370 msgid "" "Only check syntax of URLs matching the given regular expression.\n" "This option can be given multiple times." msgstr "" #: ../linkcheck/command/arg_parser.py:380 msgid "" "Check but do not recurse into URLs matching the given regular\n" "expression. This option can be given multiple times." msgstr "" #: ../linkcheck/command/arg_parser.py:390 #, fuzzy msgid "" "Read a password from console and use it for HTTP and FTP authorization.\n" "For FTP the default password is 'anonymous@'. For HTTP there is\n" "no default password. See also -u." msgstr "" "Intentar la contraseña dada para la autorización HTTP y FTP. Para FTP\n" "la contraseña por omisión es 'anonymous@'. Vea también -u." #: ../linkcheck/command/arg_parser.py:402 #, fuzzy msgid "" "Check recursively all links up to given depth. A negative depth\n" "will enable infinite recursion. Default depth is infinite." msgstr "" "Chequear recursivamente todos los enlaces hasta la profundidad\n" "dada. Una profundidad negativa habilitará la recursión infinita. Por\n" "omisión la profundidad es infinita." #: ../linkcheck/command/arg_parser.py:412 #, fuzzy msgid "Set the timeout for connection attempts in seconds." msgstr "" "Pone el tiempo de espera para intentos de conexión en segundos. El\n" "tiempo de espera por omisión es de %d segundos." #: ../linkcheck/command/arg_parser.py:421 #, fuzzy msgid "" "Try the given username for HTTP and FTP authorization.\n" "For FTP the default username is 'anonymous'. For HTTP there is\n" "no default username. See also -p." msgstr "" "Intentar el nombre de usuario dado para la autoriazación HTTP y\n" "FTP. Para FTP el nombre de usuario por omisión es 'anonymous'. Vea\n" "también -p." #: ../linkcheck/command/arg_parser.py:431 msgid "" "Specify the User-Agent string to send to the HTTP server, for example\n" "\"Mozilla/4.0\". The default is \"LinkChecker/X.Y\" where X.Y is the " "current\n" "version of LinkChecker." msgstr "" #: ../linkcheck/logger/html.py:127 ../linkcheck/logger/text.py:112 #, python-format msgid "Start checking at %s" msgstr "Se comenzó el chequeo en %s" #: ../linkcheck/logger/html.py:203 ../linkcheck/logger/text.py:165 #, python-format msgid ", line %d" msgstr ", línea %d" #: ../linkcheck/logger/html.py:205 ../linkcheck/logger/text.py:167 #, python-format msgid ", col %d" msgstr ", columna %d" #: ../linkcheck/logger/html.py:207 ../linkcheck/logger/text.py:169 #, fuzzy, python-format msgid ", page %d" msgstr ", línea %d" #: ../linkcheck/logger/html.py:246 ../linkcheck/logger/html.py:266 #: ../linkcheck/logger/text.py:185 ../linkcheck/logger/text.py:195 #, python-format msgid "%.3f seconds" msgstr "%.3f segundos" #: ../linkcheck/logger/html.py:311 ../linkcheck/logger/text.py:218 msgid "Valid" msgstr "Válido" #: ../linkcheck/logger/html.py:316 ../linkcheck/logger/text.py:221 msgid "Error" msgstr "Error" #: ../linkcheck/logger/html.py:323 msgid "Statistics" msgstr "" #: ../linkcheck/logger/html.py:327 ../linkcheck/logger/text.py:300 #, python-format msgid "" "Content types: %(image)d image, %(text)d text, %(video)d video, %(audio)d " "audio, %(application)d application, %(mail)d mail and %(other)d other." msgstr "" #: ../linkcheck/logger/html.py:335 ../linkcheck/logger/text.py:307 #, python-format msgid "URL lengths: min=%(min)d, max=%(max)d, avg=%(avg)d." msgstr "" #: ../linkcheck/logger/html.py:343 ../linkcheck/logger/text.py:315 msgid "No statistics available since no URLs were checked." msgstr "" #: ../linkcheck/logger/html.py:349 ../linkcheck/logger/text.py:231 msgid "That's it." msgstr "Eso es." #: ../linkcheck/logger/html.py:352 #, python-format msgid "%d link checked." msgid_plural "%d links checked." msgstr[0] "%d enlace chequeado." msgstr[1] "%d enlaces chequeados." #: ../linkcheck/logger/html.py:357 ../linkcheck/logger/text.py:240 #, python-format msgid "%d warning found" msgid_plural "%d warnings found" msgstr[0] "%d advertencia encontrada" msgstr[1] "%d advertencias encontradas" #: ../linkcheck/logger/html.py:362 ../linkcheck/logger/text.py:250 #, python-format msgid " (%d ignored or duplicates not printed)" msgstr "" #: ../linkcheck/logger/html.py:367 ../linkcheck/logger/text.py:255 #, python-format msgid "%d error found" msgid_plural "%d errors found" msgstr[0] "%d error encontrado" msgstr[1] "%d errores encontrados" #: ../linkcheck/logger/html.py:372 ../linkcheck/logger/text.py:265 #, python-format msgid " (%d duplicates not printed)" msgstr "" #: ../linkcheck/logger/html.py:381 ../linkcheck/logger/text.py:273 #, python-format msgid "There was %(num)d internal error." msgid_plural "There were %(num)d internal errors." msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/html.py:391 ../linkcheck/logger/__init__.py:397 #: ../linkcheck/logger/text.py:282 #, python-format msgid "Stopped checking at %(time)s (%(duration)s)" msgstr "Se paró el chequeo en %(time)s (%(duration)s)" #: ../linkcheck/logger/html.py:401 #, fuzzy, python-format msgid "Read the documentation at %s" msgstr "Obtenga la versión más reciente en %s" #: ../linkcheck/logger/html.py:411 #, python-format msgid "Write comments and bugs to %s" msgstr "Escriba comentarios y errores a %s" #: ../linkcheck/logger/failures.py:47 #, python-format msgid "%(blacklist)s file is deprecated please rename to failures" msgstr "" #: ../linkcheck/logger/failures.py:99 #, python-format msgid "invalid line starting with '%(linestart)s' in %(failures)s" msgstr "" #: ../linkcheck/logger/__init__.py:31 msgid "Real URL" msgstr "URL real" #: ../linkcheck/logger/__init__.py:32 msgid "Cache key" msgstr "Llave del \"cache\"" #: ../linkcheck/logger/__init__.py:33 msgid "Result" msgstr "Resultado" #: ../linkcheck/logger/__init__.py:34 msgid "Base" msgstr "Base" #: ../linkcheck/logger/__init__.py:35 msgid "Name" msgstr "Nombre" #: ../linkcheck/logger/__init__.py:36 msgid "Parent URL" msgstr "URL padre" #: ../linkcheck/logger/__init__.py:37 msgid "Extern" msgstr "Externo" #: ../linkcheck/logger/__init__.py:38 msgid "Info" msgstr "Información" #: ../linkcheck/logger/__init__.py:39 msgid "Warning" msgstr "Advertencia" #: ../linkcheck/logger/__init__.py:40 #, fuzzy msgid "D/L time" msgstr "Tiempo de bajada" #: ../linkcheck/logger/__init__.py:41 #, fuzzy msgid "Size" msgstr "Tamaño de bajada" #: ../linkcheck/logger/__init__.py:42 #, fuzzy msgid "Check time" msgstr "Tiempo de chequeo" #: ../linkcheck/logger/__init__.py:43 msgid "URL" msgstr "URL" #: ../linkcheck/logger/__init__.py:44 msgid "Level" msgstr "" #: ../linkcheck/logger/__init__.py:45 msgid "Modified" msgstr "" #: ../linkcheck/logger/__init__.py:275 #, python-format msgid "Happy birthday for LinkChecker, I'm %d years old today!" msgstr "¡Cumpleaños feliz para LinkChecker, cumplo %d años hoy!" #: ../linkcheck/logger/__init__.py:381 #, python-format msgid "created by %(app)s at %(time)s" msgstr "crado por %(app)s en %(time)s" #: ../linkcheck/logger/__init__.py:385 ../linkcheck/logger/text.py:105 #, fuzzy, python-format msgid "Read the documentation at %(url)s" msgstr "Obtenga la versión más reciente en %(url)s" #: ../linkcheck/logger/__init__.py:388 ../linkcheck/logger/text.py:108 #, python-format msgid "Write comments and bugs to %(url)s" msgstr "Escriba comentarios y errores a %(url)s" #: ../linkcheck/logger/text.py:65 msgid "Invalid value for wraplength. Using default." msgstr "" #: ../linkcheck/logger/text.py:230 msgid "The check has been interrupted; results are not complete." msgstr "" #: ../linkcheck/logger/text.py:232 #, fuzzy, python-format msgid "%d link" msgid_plural "%d links" msgstr[0] "%d enlace chequeado." msgstr[1] "%d enlaces chequeados." #: ../linkcheck/logger/text.py:236 #, python-format msgid "in %d URL" msgid_plural "in %d URLs" msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/text.py:238 #, fuzzy msgid " checked." msgstr "%d enlace chequeado." #: ../linkcheck/logger/text.py:292 msgid "Statistics:" msgstr "" #: ../linkcheck/logger/text.py:295 #, python-format msgid "Downloaded: %s." msgstr "" #: ../linkcheck/__init__.py:77 #, python-format msgid "Link pattern %r strict=%s" msgstr "" #: ../linkcheck/__init__.py:87 #, fuzzy, python-format msgid "invalid regular expression %r: %s" msgstr "nivel de recursión inválido" #: ../linkcheck/__init__.py:111 msgid "CRITICAL" msgstr "CRÍTICO" #: ../linkcheck/__init__.py:112 msgid "ERROR" msgstr "ERROR" #: ../linkcheck/__init__.py:113 msgid "WARN" msgstr "ADVERTENCIA" #: ../linkcheck/__init__.py:114 msgid "WARNING" msgstr "ADVERTENCIA" #: ../linkcheck/__init__.py:115 msgid "INFO" msgstr "INFORMACIÓN" #: ../linkcheck/__init__.py:116 msgid "DEBUG" msgstr "DEPURACIÓN" #: ../linkcheck/__init__.py:117 msgid "NOTSET" msgstr "NODEFINIDO" #: ../linkcheck/strformat.py:165 #, python-format msgid "%(prefix)s%(duration).02f seconds" msgstr "" #: ../linkcheck/strformat.py:170 #, python-format msgid "%d second" msgid_plural "%d seconds" msgstr[0] "%d segundos" msgstr[1] "%d segundos" #: ../linkcheck/strformat.py:171 #, python-format msgid "%d minute" msgid_plural "%d minutes" msgstr[0] "%d minutos" msgstr[1] "%d minutos" #: ../linkcheck/strformat.py:172 #, python-format msgid "%d hour" msgid_plural "%d hours" msgstr[0] "%d horas" msgstr[1] "%d horas" #: ../linkcheck/strformat.py:173 #, python-format msgid "%d day" msgid_plural "%d days" msgstr[0] "" msgstr[1] "" #: ../linkcheck/strformat.py:174 #, python-format msgid "%d year" msgid_plural "%d years" msgstr[0] "" msgstr[1] "" #: ../linkcheck/strformat.py:245 #, python-format msgid "" "Could not import %(module)s for %(feature)s. Install %(module)s from %(url)s " "to use this feature." msgstr "" #: ../linkcheck/cache/robots_txt.py:77 #, python-format msgid "Relative Sitemap %s in %s discarded" msgstr "" #: ../linkcheck/loader.py:40 #, python-format msgid "WARN: could not load module %s: %s" msgstr "" #: ../linkcheck/loader.py:57 #, fuzzy, python-format msgid "WARN: could not load file %s: %s" msgstr "No se pudieron almacenar las \"cookies\": %s." #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:228 #, python-format msgid "%(heading)s:" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:300 #, fuzzy msgid "usage: " msgstr "Uso: %s\n" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:726 #, python-format msgid " (default: %(default)s)" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:780 #, python-format msgid "argument %(argument_name)s: %(message)s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:886 msgid ".__call__() not defined" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1157 msgid "show program's version number and exit" msgstr "mostrar número de versión del programa" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1219 #, fuzzy, python-format msgid "conflicting subparser: %s" msgstr "Opciones deprecadas" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1223 #, fuzzy, python-format msgid "conflicting subparser alias: %s" msgstr "Opciones deprecadas" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1258 #, python-format msgid "unknown parser %(parser_name)r (choices: %(choices)s)" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1318 #, python-format msgid "argument \"-\" with mode %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1327 #, python-format msgid "can't open '%(filename)s': %(error)s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1536 #, python-format msgid "cannot merge actions - two groups are named %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1574 msgid "'required' is an invalid argument for positionals" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1596 #, python-format msgid "" "invalid option string %(option)r: must start with a character " "%(prefix_chars)r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1614 #, python-format msgid "dest= is required for options like %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1631 #, python-format msgid "invalid conflict_resolution value: %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1649 #, fuzzy, python-format msgid "conflicting option string: %s" msgid_plural "conflicting option strings: %s" msgstr[0] "Opciones deprecadas" msgstr[1] "Opciones deprecadas" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1723 msgid "mutually exclusive arguments must be optional" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1799 #, fuzzy msgid "positional arguments" msgstr "la opción %s requiere un argumento" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1800 #, fuzzy msgid "options" msgstr "Opciones de salida" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1815 msgid "show this help message and exit" msgstr "mostrar este mensaje de ayuda y salir" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1846 msgid "cannot have multiple subparser arguments" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1898 #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2421 #, python-format msgid "unrecognized arguments: %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2001 #, python-format msgid "not allowed with argument %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2043 #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2074 #, python-format msgid "ignored explicit argument %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2181 #, python-format msgid "the following arguments are required: %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2196 #, python-format msgid "one of the arguments %s is required" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2240 msgid "expected one argument" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2241 msgid "expected at most one argument" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2242 msgid "expected at least one argument" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2246 #, python-format msgid "expected %s argument" msgid_plural "expected %s arguments" msgstr[0] "" msgstr[1] "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2303 #, fuzzy, python-format msgid "ambiguous option: %(option)s could match %(matches)s" msgstr "opción ambigua: %s (¿%s?)" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2364 #, fuzzy, python-format msgid "unexpected option string: %s" msgstr "Opciones deprecadas" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2566 #, python-format msgid "%r is not callable" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2582 #, fuzzy, python-format msgid "invalid %(type)s value: %(value)r" msgstr "opción %s: inválido %s valor: %r" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2593 #, fuzzy, python-format msgid "invalid choice: %(value)r (choose from %(choices)s)" msgstr "opción %s: opción inválida: %r (escoja de %s)" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2671 #, fuzzy, python-format msgid "%(prog)s: error: %(message)s\n" msgstr "extern%d: error de sintaxis %s\n" #~ msgid "No NNTP server was specified, skipping this URL." #~ msgstr "No se especificó un servidor NNTP, pasando por alto este URL." #, python-format #~ msgid "Article number %(num)s found." #~ msgstr "Se encontró el artículo número %(num)s." #~ msgid "No newsgroup specified in NNTP URL." #~ msgstr "No se especificó ningún grupo de noticias en el URL NTTP." #, fuzzy, python-format #~ msgid "NNTP server too busy; tried more than %d times." #~ msgstr "" #~ "El servidor NTTP está demasiado ocupado; se intentó más de %d veces." #~ msgid "Host is empty" #~ msgstr "El servidor está vacío" #~ msgid "" #~ "Specify an NNTP server for 'news:...' links. Default is the\n" #~ "environment variable NNTP_SERVER. If no host is given,\n" #~ "only the syntax of the link is checked." #~ msgstr "" #~ "Especificar un servidor NNTP para enlaces 'news:...'. Por omisión es\n" #~ "la variable del entorno NNTP_SERVER. Si no se da un anfitrión, sólo se\n" #~ "chequea la sintaxis del enlace." #, fuzzy #~ msgid "optional arguments" #~ msgstr "la opción %s requiere un argumento" #~ msgid "The URL has been ignored." #~ msgstr "URL ignorado." #, fuzzy #~ msgid "Anchor check plugin is broken. Fixes welcome." #~ msgstr "Error de sintaxis en %(arg)r: %(msg)s" #~ msgid "Ignoring proxy setting `%(proxy)s'." #~ msgstr "Ignorando el ajuste del proxy `%(proxy)s'" #~ msgid "Using proxy `%(proxy)s'." #~ msgstr "Usando Proxy `%(proxy)s'." linkchecker-10.5.0/po/fr.po000066400000000000000000001637441466565367000155050ustar00rootroot00000000000000# traduction de fr.po en français # French translation for LinkChecker. # Jerome Couderc , 2000. # Yann Verley , 2004, 2005. # Francois Boulogne 2012. # msgid "" msgstr "" "Project-Id-Version: LinkChecker\n" "Report-Msgid-Bugs-To: https://github.com/linkchecker/linkchecker\n" "POT-Creation-Date: 2024-08-27 18:47+0000\n" "PO-Revision-Date: 2011-02-16 15:27+0100\n" "Last-Translator: Bastian Kleineidam \n" "Language-Team: français \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.9.1\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../linkcheck/director/__init__.py:36 #, fuzzy, python-format msgid "Problem using login URL: %(msg)s." msgstr "Erreur : %s" #: ../linkcheck/director/__init__.py:39 #, fuzzy, python-format msgid "Error using login URL: %(msg)s." msgstr "Erreur : %s" #: ../linkcheck/director/__init__.py:44 #, fuzzy, python-format msgid "Error starting log output: %(msg)s." msgstr "Erreur : %s" #: ../linkcheck/director/__init__.py:60 msgid "" "Could not start a new thread. Check that the current user is allowed to " "start new threads." msgstr "" #: ../linkcheck/director/__init__.py:93 #, fuzzy msgid "interrupt; waiting for active threads to finish" msgstr "interruption clavier ; en attente de la terminaison d' %d thread actif" #: ../linkcheck/director/__init__.py:94 msgid "another interrupt will exit immediately" msgstr "" #: ../linkcheck/director/__init__.py:110 #, fuzzy msgid "user abort; force shutdown" msgstr "interruption clavier ; en attente de la terminaison d' %d thread actif" #: ../linkcheck/director/aggregator.py:54 #, fuzzy, python-format msgid "Could not parse cookie file: %s. %s" msgstr "Impossible d'enregistrer les cookies : %(msg)s." #: ../linkcheck/director/aggregator.py:188 msgid "These URLs are still active:" msgstr "" #: ../linkcheck/director/aggregator.py:200 #, python-format msgid "" "%(num)d URLs are still active. After a timeout of %(timeout)s the active " "URLs will stop." msgstr "" #: ../linkcheck/director/console.py:38 #, fuzzy, python-format msgid "%2d thread active" msgid_plural "%2d threads active" msgstr[0] "%2d thread actif," msgstr[1] "%2d threads actifs," #: ../linkcheck/director/console.py:40 #, fuzzy, python-format msgid "%5d link queued" msgid_plural "%5d links queued" msgstr[0] "%5d URL mise en file," msgstr[1] "%5d URL mises en file," #: ../linkcheck/director/console.py:42 #, python-format msgid "%4d link" msgid_plural "%4d links" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:44 #, python-format msgid "%3d URL" msgid_plural "%3d URLs" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:46 #, python-format msgid "runtime %s" msgstr "temps d'exécution %s" #: ../linkcheck/director/console.py:66 #, fuzzy, python-format msgid "" "********** Oops, I did it again. *************\n" "\n" "You have found an internal error in LinkChecker. Please write a bug report\n" "at %s\n" "and include the following information:\n" "- the URL or file you are testing\n" "- the system information below\n" "\n" "When using the commandline client:\n" "- your commandline arguments and any custom configuration files.\n" "- the output of a debug run with option \"-Dall\"\n" "\n" "Not disclosing some of the information above due to privacy reasons is ok.\n" "I will try to help you nonetheless, but you have to give me something\n" "I can work with ;) .\n" msgstr "" "********** Oops, I did it again. *************\n" "\n" "Vous avez trouvé une erreur interne dans LinkChecker. Merci d'écrire un\n" "rapport de bogue (en anglais) à\n" " http://sourceforge.net/tracker/?func=add&group_id=1913&atid=101913\n" "ou envoyez un mail à %s et incluez les informations suivantes:\n" "- l'URL ou le fichier que vous testiez\n" "- les arguments de la ligne de commande et/ou la configuration.\n" "- la sortie d'une exécution en mode debug, avec l'option « -Dall » pour la " "commande\n" "- en dessous, les informations sur votre système.\n" "\n" "Si vous ne voulez pas révéler certaines informations pour préserver\n" "votre vie privée, il n'y a pas de problème. J'essaierai néanmoins de vous\n" "aider, mais il faudra que vous me donniez quelque chose avec quoi\n" "je peux travailler ;).\n" #: ../linkcheck/director/console.py:94 #, fuzzy msgid "******** LinkChecker internal error, over and out ********" msgstr "******** Erreur interne de LinkChecker, sortie ********" #: ../linkcheck/director/console.py:140 msgid "System info:" msgstr "Info système :" #: ../linkcheck/director/console.py:142 msgid "Released on:" msgstr "" #: ../linkcheck/director/console.py:144 ../linkcheck/command/linkchecker.py:130 #, fuzzy, python-format msgid "Python %(version)s on %(platform)s" msgstr "Python %s sur %s" #: ../linkcheck/director/console.py:152 #, fuzzy msgid "Local time:" msgstr "Temps D/L" #: ../linkcheck/director/console.py:153 msgid "sys.argv:" msgstr "" #: ../linkcheck/director/console.py:158 msgid "released" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:56 msgid "HTML syntax check plugin is broken. Fixes welcome." msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:74 #, fuzzy msgid "valid HTML syntax" msgstr "Syntaxe mail invalide" #: ../linkcheck/plugins/syntaxchecks.py:81 #, python-format msgid "HTML syntax check plugin error: %(msg)s " msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:114 #, fuzzy msgid "valid CSS syntax" msgstr "Syntaxe mail invalide" #: ../linkcheck/plugins/syntaxchecks.py:121 #, python-format msgid "CSS syntax check plugin error: %(msg)s " msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:132 #, python-format msgid "%(w3type)s validation error at line %(line)s col %(column)s: %(msg)s" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:136 #, python-format msgid "%(w3type)s validation error at line %(line)s: %(msg)s" msgstr "" #: ../linkcheck/plugins/markdowncheck.py:88 #: ../linkcheck/plugins/regexcheck.py:45 #, python-format msgid "Invalid regex pattern %r: %s" msgstr "" #: ../linkcheck/plugins/regexcheck.py:61 #, fuzzy, python-format msgid "Found %(match)r at line %(line)d in link contents." msgstr "%r trouvé dans le contenu du lien." #: ../linkcheck/plugins/sslcertcheck.py:70 msgid "certificate did not include \"notAfter\" information" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:73 msgid "SSL verification is disabled; enable the sslverify option" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:85 #, python-format msgid "Invalid SSL certificate \"notAfter\" value %r" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:94 #, python-format msgid "SSL certificate is expired on %(expire)s." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:100 #, python-format msgid "SSL certificate expires on %(expire)s and is only %(valid)s valid." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:104 #, python-format msgid "SSL certificate expires on %(expire)s and is %(valid)s valid." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:118 #: ../linkcheck/configuration/confparse.py:98 #: ../linkcheck/configuration/confparse.py:116 #, python-format msgid "invalid value for %s: %d must not be less than %d" msgstr "" #: ../linkcheck/plugins/locationinfo.py:46 #, python-format msgid "URL is located in %(location)s." msgstr "" #: ../linkcheck/plugins/viruscheck.py:101 msgid "clamd is not ready for stream scanning" msgstr "" #: ../linkcheck/plugins/viruscheck.py:160 msgid "ScannerDaemonOutputFormat must be disabled" msgstr "" #: ../linkcheck/plugins/viruscheck.py:163 msgid "only one of TCPSocket and LocalSocket must be enabled" msgstr "" #: ../linkcheck/plugins/viruscheck.py:193 msgid "one of TCPSocket or LocalSocket must be enabled" msgstr "" #: ../linkcheck/plugins/viruscheck.py:229 #, fuzzy msgid "Could not connect to ClamAV daemon." msgstr "Impossible de se connecter, mais la syntaxe est correcte" #: ../linkcheck/plugins/anchorcheck.py:70 #, fuzzy, python-format msgid "Anchor `%(name)s' (decoded: `%(decoded)s') not found." msgstr "Impossible de trouver l'ancre `%(name)s'." #: ../linkcheck/plugins/anchorcheck.py:71 #, python-format msgid "Available anchors: %(anchors)s." msgstr "" #: ../linkcheck/cookies.py:46 #, fuzzy msgid "No entries found" msgstr "Aucun serveur NNTP spécifié, l'URL est ignorée." #: ../linkcheck/cmdline.py:61 #, fuzzy, python-format msgid "Error: %(msg)s" msgstr "Erreur : %s" #: ../linkcheck/cmdline.py:63 #, fuzzy, python-format msgid "Execute '%(program)s -h' for help" msgstr "Lancez la commande « linkchecker -h » pour obtenir l'aide" #: ../linkcheck/configuration/__init__.py:227 #, python-format msgid "Configuration file %r does not exist." msgstr "" #: ../linkcheck/configuration/__init__.py:229 #, python-format msgid "Configuration file %r is not readable." msgstr "" #: ../linkcheck/configuration/__init__.py:239 msgid "missing user or URL pattern in authentication data." msgstr "" #: ../linkcheck/configuration/__init__.py:274 msgid "activating text logger output." msgstr "" #: ../linkcheck/configuration/__init__.py:285 msgid "no user/password authentication data found for login URL." msgstr "" #: ../linkcheck/configuration/__init__.py:289 msgid "login URL is not a HTTP URL." msgstr "" #: ../linkcheck/configuration/__init__.py:293 msgid "login URL is incomplete." msgstr "" #: ../linkcheck/configuration/__init__.py:296 #, fuzzy, python-format msgid "disabling login URL %(url)s." msgstr "Erreur : %s" #: ../linkcheck/configuration/__init__.py:349 #, python-format msgid "could not create plugin directory %(dirname)r: %(errmsg)r" msgstr "" #: ../linkcheck/configuration/__init__.py:397 #, python-format msgid "" "could not copy initial configuration file %(src)r to %(dst)r: %(errmsg)r" msgstr "" #: ../linkcheck/configuration/confparse.py:62 #, python-format msgid "configuration files %s contain no sections." msgstr "" #: ../linkcheck/configuration/confparse.py:75 #, fuzzy, python-format msgid "Error parsing configuration: %s" msgstr "Erreur : %s" #: ../linkcheck/configuration/confparse.py:83 #, python-format msgid "invalid empty value for %s: %s\n" msgstr "" #: ../linkcheck/configuration/confparse.py:103 #: ../linkcheck/configuration/confparse.py:121 #, python-format msgid "invalid value for %s: %d must not be greater than %d" msgstr "" #: ../linkcheck/configuration/confparse.py:136 msgid "" "The blacklist section in linkcheckerrc is deprecated, please rename to " "failures" msgstr "" #: ../linkcheck/configuration/confparse.py:237 #, python-format msgid "missing auth part in entry %(val)r" msgstr "" #: ../linkcheck/configuration/confparse.py:247 #, python-format msgid "invalid login URL `%s'. Only HTTP and HTTPS URLs are supported." msgstr "" #: ../linkcheck/configuration/confparse.py:276 #, python-format msgid "" "The configuration file %s contains password information (in section [%s] and " "options %s) and the file is readable by others. Please make the file only " "readable by you." msgstr "" #: ../linkcheck/configuration/confparse.py:285 #, python-format msgid "For example execute 'chmod go-rw %s'." msgstr "" #: ../linkcheck/configuration/confparse.py:290 #, python-format msgid "See %(url)s for more info on setting file permissions." msgstr "" #: ../linkcheck/lc_cgi.py:215 #, fuzzy, python-format msgid "could not set locale %r: %s" msgstr "Impossible d'analyser le contenu : %(msg)r" #: ../linkcheck/lc_cgi.py:217 #, fuzzy, python-format msgid "unsupported language %r" msgstr "langage non accepté" #: ../linkcheck/lc_cgi.py:222 msgid "empty url was given" msgstr "Une URL vide a été donnée." #: ../linkcheck/lc_cgi.py:224 #, fuzzy, python-format msgid "disallowed url %r was given" msgstr "Une URL non autorisée a été donnée." #: ../linkcheck/lc_cgi.py:226 msgid "no url was given" msgstr "Aucune URL donnée" #: ../linkcheck/lc_cgi.py:231 #, fuzzy, python-format msgid "invalid recursion level %r" msgstr "Niveau de récursion invalide" #: ../linkcheck/lc_cgi.py:237 #, fuzzy, python-format msgid "invalid %s option %r" msgstr "option de journal %r invalide" #: ../linkcheck/lc_cgi.py:264 #, fuzzy, python-format msgid "" "\n" "\n" "\n" "LinkChecker Online Error\n" "\n" "
\n" "Error: %s
\n" "The LinkChecker Online script has encountered an error. Please ensure\n" "that your provided URL link begins with http:// and\n" "contains only these characters: A-Za-z0-9./_~-

\n" "Errors are logged.\n" "
\n" "\n" "" msgstr "" "\n" "Erreur en ligne de LinkChecker\n" "\n" "
\n" "Erreur : %s
\n" "Le script en ligne de LinkChecker a rencontré une erreur. Veuillez vous " "assurer\n" "que l'URL fournie commence par http:// et\n" "ne contient que les caractères suivants : A-Za-z0-9./_~-

\n" "Les erreurs sont inscrites dans le journal.\n" "
\n" "\n" "" #: ../linkcheck/checker/fileurl.py:142 #, fuzzy, python-format msgid "Could not get current working directory: %(msg)s" msgstr "Impossible d'analyser le contenu : %(msg)r" #: ../linkcheck/checker/fileurl.py:175 ../linkcheck/checker/fileurl.py:339 msgid "Added trailing slash to directory." msgstr "Rajout d'une barre oblique terminale au répertoire." #: ../linkcheck/checker/fileurl.py:198 ../linkcheck/checker/fileurl.py:352 msgid "" "local files are only checked without parent URL or when the parent URL is " "also a file" msgstr "" #: ../linkcheck/checker/fileurl.py:203 ../linkcheck/checker/fileurl.py:367 msgid "directory" msgstr "répertoire" #: ../linkcheck/checker/fileurl.py:222 #, fuzzy, python-format msgid "" "The URL path %(path)r is not the same as the system path %(realpath)r. You " "should always use the system path in URLs." msgstr "" "L'URL %r n'est pas la même que le chemin du système %r. Vous devez toujours " "utiliser le chemin du système dans les URL." #: ../linkcheck/checker/fileurl.py:360 #, python-format msgid "" "URL `%s' is a directory with an anchor. When checking local files " "AnchorCheck does not support anchors for directories." msgstr "" #: ../linkcheck/checker/itmsservicesurl.py:31 msgid "Missing required url parameter" msgstr "" #: ../linkcheck/checker/urlbase.py:79 #, python-format msgid "URL has unparsable domain name: %(name)s" msgstr "" #: ../linkcheck/checker/urlbase.py:163 #, fuzzy msgid "The URL is outside of the domain filter, checked only syntax." msgstr "En dehors du filtre de domaine, analyse de la syntaxe seulement." #: ../linkcheck/checker/urlbase.py:166 msgid "filtered" msgstr "" #: ../linkcheck/checker/urlbase.py:216 #, python-format msgid "Leading or trailing whitespace in URL `%(url)s'." msgstr "" #: ../linkcheck/checker/urlbase.py:340 #, python-format msgid "The URL with content type %r is not parseable." msgstr "" #: ../linkcheck/checker/urlbase.py:445 msgid "URL is empty" msgstr "L'URL est vide." #: ../linkcheck/checker/urlbase.py:460 #, fuzzy, python-format msgid "Effective URL %(url)r." msgstr "URL effective %r." #: ../linkcheck/checker/urlbase.py:467 #, fuzzy, python-format msgid "URL length %(len)d is longer than %(max)d." msgstr "La taille du contenu (%s) est supérieure à %s." #: ../linkcheck/checker/urlbase.py:517 ../linkcheck/checker/urlbase.py:523 #, fuzzy, python-format msgid "URL host %(host)r has invalid port" msgstr "Le port %r de l'URL est invalide." #: ../linkcheck/checker/urlbase.py:530 #, fuzzy msgid "URL has empty hostname" msgstr "L'URL est vide." #: ../linkcheck/checker/urlbase.py:555 #, python-format msgid "URL %(url)s has obfuscated IP address %(ip)s" msgstr "" #: ../linkcheck/checker/urlbase.py:591 msgid "Hostname not found" msgstr "Impossible de trouver le nom d'hôte" #: ../linkcheck/checker/urlbase.py:594 #, python-format msgid "Bad hostname %(host)r: %(msg)s" msgstr "" #: ../linkcheck/checker/urlbase.py:614 #, fuzzy, python-format msgid "could not get content: %(msg)s" msgstr "Impossible d'analyser le contenu : %(msg)r" #: ../linkcheck/checker/urlbase.py:669 #, fuzzy, python-format msgid "Content size %(size)s is larger than %(maxbytes)s." msgstr "La taille du contenu (%s) est supérieure à %s." #: ../linkcheck/checker/urlbase.py:763 msgid "Content size is zero." msgstr "La taille du contenu est nulle." #: ../linkcheck/checker/urlbase.py:800 ../linkcheck/checker/httpurl.py:348 msgid "File size too large" msgstr "" #: ../linkcheck/checker/urlbase.py:881 #, python-format msgid "URL has unparsable domain name: %(domain)s" msgstr "" #: ../linkcheck/checker/unknownurl.py:32 #, fuzzy, python-format msgid "%(scheme)s URL ignored." msgstr "URL %s ignorée." #: ../linkcheck/checker/unknownurl.py:34 #, fuzzy msgid "ignored" msgstr "URL %s ignorée." #: ../linkcheck/checker/unknownurl.py:36 msgid "URL is unrecognized or has invalid syntax" msgstr "L'URL n'est pas reconnue ou n'a pas une syntaxe valide." #: ../linkcheck/checker/mailtourl.py:88 #, fuzzy, python-format msgid "No mail addresses or email subject found in `%(url)s'." msgstr "Aucune adresse trouvée." #: ../linkcheck/checker/mailtourl.py:132 #, python-format msgid "Error parsing CGI values: %s" msgstr "" #: ../linkcheck/checker/mailtourl.py:158 #, python-format msgid "" "Mail address `%(addr)s' too long. Allowed 256 chars, was %(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:168 #, python-format msgid "Missing `@' in mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:177 #, python-format msgid "Missing local part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:184 #, python-format msgid "Missing domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:192 #, python-format msgid "" "Local part of mail address `%(addr)s' too long. Allowed 64 chars, was " "%(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:203 #, python-format msgid "" "Domain part of mail address `%(addr)s' too long. Allowed 255 chars, was " "%(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:218 #, python-format msgid "Unquoted double quote or backslash in mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:227 #, python-format msgid "Local part of mail address `%(addr)s' may not start with a dot." msgstr "" #: ../linkcheck/checker/mailtourl.py:235 #, python-format msgid "Local part of mail address `%(addr)s' may not end with a dot." msgstr "" #: ../linkcheck/checker/mailtourl.py:243 #, python-format msgid "Local part of mail address `%(addr)s' may not contain two dots." msgstr "" #: ../linkcheck/checker/mailtourl.py:253 #, python-format msgid "" "Local part of mail address `%(addr)s' contains unquoted character `%(char)s." msgstr "" #: ../linkcheck/checker/mailtourl.py:271 #, python-format msgid "Domain part of mail address `%(addr)s' has invalid IP." msgstr "" #: ../linkcheck/checker/mailtourl.py:281 #, python-format msgid "Invalid domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:289 #, python-format msgid "Invalid top level domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:327 #, python-format msgid "No MX mail host for %(domain)s found." msgstr "Aucun hôte de messagerie trouvé pour %(domain)s." #: ../linkcheck/checker/mailtourl.py:336 #, fuzzy, python-format msgid "No host for %(domain)s found." msgstr "Aucun hôte de messagerie trouvé pour %(domain)s." #: ../linkcheck/checker/mailtourl.py:353 #, python-format msgid "Got invalid DNS answer %(answer)s for %(domain)s." msgstr "" #: ../linkcheck/checker/mailtourl.py:366 #, fuzzy msgid "Valid mail address syntax" msgstr "Syntaxe mail invalide" #: ../linkcheck/checker/const.py:99 msgid "The effective URL is different from the original." msgstr "" #: ../linkcheck/checker/const.py:100 msgid "Could not get the content of the URL." msgstr "" #: ../linkcheck/checker/const.py:101 msgid "The URL content size is too large." msgstr "" #: ../linkcheck/checker/const.py:102 msgid "The URL content size is zero." msgstr "" #: ../linkcheck/checker/const.py:103 msgid "The URL content type is not parseable." msgstr "" #: ../linkcheck/checker/const.py:104 msgid "The URL is longer than the recommended size." msgstr "" #: ../linkcheck/checker/const.py:105 msgid "The URL contains leading or trailing whitespace." msgstr "" #: ../linkcheck/checker/const.py:106 msgid "The file: URL is missing a trailing slash." msgstr "" #: ../linkcheck/checker/const.py:108 #, fuzzy msgid "The file: path is not the same as the system specific path." msgstr "" "L'URL %r n'est pas la même que le chemin du système %r. Vous devez toujours " "utiliser le chemin du système dans les URL." #: ../linkcheck/checker/const.py:111 msgid "A local directory with an anchor, not supported by AnchorCheck." msgstr "" #: ../linkcheck/checker/const.py:112 msgid "The ftp: URL is missing a trailing slash." msgstr "" #: ../linkcheck/checker/const.py:113 msgid "The URL had no content." msgstr "" #: ../linkcheck/checker/const.py:114 msgid "An error occurred while storing a cookie." msgstr "" #: ../linkcheck/checker/const.py:115 msgid "The URL request was rate limited." msgstr "" #: ../linkcheck/checker/const.py:116 msgid "Redirected to a different URL." msgstr "" #: ../linkcheck/checker/const.py:117 msgid "The mail MX host could not be found." msgstr "" #: ../linkcheck/checker/const.py:118 msgid "The IP is obfuscated." msgstr "" #: ../linkcheck/checker/const.py:119 msgid "XML could not be parsed." msgstr "" #: ../linkcheck/checker/ftpurl.py:75 msgid "Got no answer from FTP server" msgstr "Pas de réponse du serveur FTP" #: ../linkcheck/checker/ftpurl.py:78 #, fuzzy, python-format msgid "Remote host has closed connection: %(msg)s" msgstr "L'hôte distant a fermé la connexion : %r" #: ../linkcheck/checker/ftpurl.py:124 msgid "Missing trailing directory slash in ftp url." msgstr "Barre oblique terminale manquante dans l'URL FTP." #: ../linkcheck/checker/ftpurl.py:188 msgid "FTP file size too large" msgstr "" #: ../linkcheck/checker/httpurl.py:138 #, fuzzy msgid "Access denied by robots.txt, checked only syntax." msgstr "Accès refusé par robots.txt, analyse de la syntaxe seulement." #: ../linkcheck/checker/httpurl.py:139 msgid "syntax OK" msgstr "" #: ../linkcheck/checker/httpurl.py:283 #, fuzzy, python-format msgid "Redirected to `%(url)s' status: %(code)d %(reason)s." msgstr "Redirigé vers %(url)s." #: ../linkcheck/checker/httpurl.py:336 msgid "OK" msgstr "" #: ../linkcheck/checker/dnsurl.py:46 #, python-format msgid "%(host)s resolved to IPs %(ips)s" msgstr "" #: ../linkcheck/checker/dnsurl.py:48 #, python-format msgid "%(host)r could not be resolved" msgstr "" #: ../linkcheck/command/setup_config.py:49 msgid "Running with python -O disables debugging." msgstr "" #: ../linkcheck/command/setup_config.py:81 #, python-format msgid "blacklist is deprecated for option %(option)s, using failures instead" msgstr "" #: ../linkcheck/command/setup_config.py:87 #: ../linkcheck/command/setup_config.py:133 #, fuzzy, python-format msgid "Unknown logger type %(type)r in %(output)r for option %(option)s" msgstr "Type d'enregistreur de journal %r inconnu dans %r pour l'option %s" #: ../linkcheck/command/setup_config.py:94 #: ../linkcheck/command/setup_config.py:144 #, fuzzy, python-format msgid "Unknown encoding %(encoding)r in %(output)r for option %(option)s" msgstr "Encodage %r inconnu dans %r pour l'option %s" #: ../linkcheck/command/setup_config.py:127 #, python-format msgid "" "blacklist logger is deprecated for option %(option)s, using failures instead" msgstr "" #: ../linkcheck/command/setup_config.py:159 #, python-format msgid "Enter LinkChecker HTTP/FTP password for user %(user)s:" msgstr "" #: ../linkcheck/command/setup_config.py:163 msgid "Enter LinkChecker HTTP/FTP password:" msgstr "" #: ../linkcheck/command/setup_config.py:181 #, fuzzy, python-format msgid "Illegal argument %(arg)r for option %(option)s" msgstr "Argument %r illégal pour l'option %s" #: ../linkcheck/command/setup_config.py:198 #, python-format msgid "Enter LinkChecker password for user %(user)s at %(strpattern)s:" msgstr "" #: ../linkcheck/command/setup_config.py:207 #, python-format msgid "Cookie file %s does not exist." msgstr "" #: ../linkcheck/command/setup_config.py:210 #, fuzzy, python-format msgid "Could not read cookie file %s" msgstr "Impossible d'enregistrer les cookies : %(msg)s." #: ../linkcheck/command/linkchecker.py:50 msgid "Running as root user; dropping privileges by changing user to nobody." msgstr "" #: ../linkcheck/command/linkchecker.py:124 #, python-format msgid "Invalid debug level %(level)r" msgstr "" #: ../linkcheck/command/linkchecker.py:140 #, python-format msgid "Config file %s does not exist." msgstr "" #: ../linkcheck/command/linkchecker.py:143 #, fuzzy, python-format msgid "Could not read config file %s." msgstr "Impossible d'enregistrer les cookies : %(msg)s." #: ../linkcheck/command/linkchecker.py:176 #, fuzzy msgid "no files or URLs given" msgstr "aucun fichier ou URL donné" #: ../linkcheck/command/linkchecker.py:184 #, fuzzy, python-format msgid "" "Overwrite profiling file %(file)r?\n" "Press Ctrl-C to cancel, RETURN to continue." msgstr "" "Écraser le fichier de profilage %r ?\n" "Appuyez sur Ctrl-C pour annuler, Retour pour continuer." #: ../linkcheck/command/linkchecker.py:192 msgid "Canceled." msgstr "Annulé." #: ../linkcheck/command/linkchecker.py:199 msgid "" "The `yappi' Python module is not installed, therefore the --profile option " "is disabled." msgstr "" #: ../linkcheck/command/linkchecker.py:218 msgid "Dumping memory statistics..." msgstr "" #: ../linkcheck/command/linkchecker.py:220 #, python-format msgid "The memory dump has been written to `%(filename)s'." msgstr "" #: ../linkcheck/command/arg_parser.py:28 #, fuzzy msgid "" "NOTES\n" " o URLs on the command line starting with \"ftp.\" are treated like\n" " \"ftp://ftp.\", URLs starting with \"www.\" are treated like \"http://www." "\".\n" " You can also give local files as arguments.\n" " o If you have your system configured to automatically establish a\n" " connection to the internet (e.g. with diald), it will connect when\n" " checking links not pointing to your local system.\n" " See the --ignore-url option on how to prevent this.\n" " o Javascript links are currently ignored.\n" " o If your platform does not support threading, LinkChecker disables it\n" " automatically.\n" " o You can supply multiple user/password pairs in a configuration file.\n" msgstr "" "NOTES\n" "o Les URL sur la ligne de commande commençant par « ftp. » sont traitées\n" " comme « ftp://ftp. », les URL commençant par « www. » sont traitées\n" " comme « http://www. ».\n" " Vous pouvez aussi mettre des noms de fichiers locaux comme arguments.\n" "o Si votre système est configuré pour établir automatiquement une\n" " connexion à internet (par exemple, avec diald), il se connectera quand\n" " les liens de vérification ne pointent pas sur votre système local.\n" " Regardez l'option --extern-strict-all pour savoir comment éviter cela.\n" "o Les liens javascript sont ignorés actuellement.\n" "o Si votre plate-forme n'accepte pas le multithreading, LinkChecker le\n" " désactive automatiquement.\n" "o Vous pouvez fournir plusieurs paires nom d'utilisateur/mot de passe dans\n" " un fichier de configuration.\n" "o Pour utiliser les proxys, positionnez $http_proxy, $https_proxy,\n" " $ftp_proxy, sur Unix ou Windows.\n" " Sur un Mac, utilisez la configuration Internet.\n" "o Pour la vérification des liens « news: », les liens de l'hôte NNTP donné\n" " n'ont pas besoin d'être les mêmes que l'hôte de l'utilisateur naviguant\n" " dans vos pages !\n" #: ../linkcheck/command/arg_parser.py:44 msgid "" "PROXY SUPPORT\n" "To use a proxy on Unix or Windows set $http_proxy or $https_proxy\n" "to the proxy URL. The URL should be of the form\n" "\"http://[:@][:]\".\n" "LinkChecker also detects manual proxy settings of Internet Explorer under\n" "Windows systems. On a Mac use the Internet Config to select a proxy.\n" "\n" "LinkChecker honors the $no_proxy environment variable. It can be a list\n" "of domain names for which no proxy will be used.\n" "\n" "Setting a HTTP proxy on Unix for example looks like this:\n" "\n" " export http_proxy=\"http://proxy.example.com:8080\"\n" "\n" "Proxy authentication is also supported:\n" "\n" " export http_proxy=\"http://user1:mypass@proxy.example.org:8081\"\n" "\n" "Setting a proxy on the Windows command prompt:\n" "\n" " set http_proxy=http://proxy.example.com:8080\n" "\n" msgstr "" #: ../linkcheck/command/arg_parser.py:70 msgid "" "REGULAR EXPRESSIONS\n" "Only Python regular expressions are accepted by LinkChecker.\n" "See https://docs.python.org/howto/regex.html for an introduction in\n" "regular expressions.\n" "\n" "The only addition is that a leading exclamation mark negates\n" "the regular expression.\n" msgstr "" #: ../linkcheck/command/arg_parser.py:81 msgid "" "COOKIE FILES\n" "A cookie file contains standard RFC 805 header data with the following\n" "possible names:\n" "Scheme (optional)\n" " Sets the scheme the cookies are valid for; default scheme is 'http'.\n" "Host (required)\n" " Sets the domain the cookies are valid for.\n" "Path (optional)\n" " Gives the path the cookies are value for; default path is '/'.\n" "Set-cookie (optional)\n" " Set cookie name/value. Can be given more than once.\n" "\n" "Multiple entries are separated by a blank line.\n" "\n" "The example below will send two cookies to all URLs starting with\n" "'http://example.org/hello/' and one to all URLs starting\n" "with 'https://example.com/':\n" "\n" "Host: example.org\n" "Path: /hello\n" "Set-cookie: ID=\"smee\"\n" "Set-cookie: spam=\"egg\"\n" "\n" "Scheme: https\n" "Host: example.com\n" "Set-cookie: baggage=\"elitist\"; comment=\"hologram\"\n" msgstr "" #: ../linkcheck/command/arg_parser.py:111 #, fuzzy msgid "" "RETURN VALUE\n" "The return value is non-zero when\n" " o invalid links were found or\n" " o warnings were found warnings are enabled\n" " o a program error occurred\n" msgstr "" "DIAGNOSTICS\n" "Le code de retour est différent de 0 quand\n" " o il y a eu des liens non valides,\n" " o il y a eu des avertissements sur les liens et l'option --warnings était " "positionnée,\n" " o il y a eu une erreur dans le programme.\n" #: ../linkcheck/command/arg_parser.py:120 #, fuzzy msgid "" "EXAMPLES\n" "The most common use checks the given domain recursively, plus any\n" "single URL pointing outside of the domain:\n" " linkchecker http://www.example.org/\n" "Beware that this checks the whole site which can have several hundred\n" "thousands URLs. Use the -r option to restrict the recursion depth.\n" "\n" "Don't connect to mailto: hosts, only check their URL syntax. All other\n" "links are checked as usual:\n" " linkchecker --ignore-url=^mailto: www.example.org\n" "\n" "Checking local HTML files on Unix:\n" " linkchecker ../bla.html subdir/blubber.html\n" "\n" "Checking a local HTML file on Windows:\n" " linkchecker c:\\temp\\test.html\n" "\n" "You can skip the \"http://\" url part if the domain starts with \"www.\":\n" " linkchecker www.example.de\n" "\n" "You can skip the \"ftp://\" url part if the domain starts with \"ftp.\":\n" " linkchecker -r0 ftp.example.org\n" msgstr "" "EXEMPLES\n" "L'utilisation la plus courante est de vérifier le domaine donné " "récursivement,\n" "ainsi que quelques URL simples pointant en dehors du domaine :\n" " linkchecker http://treasure.calvinsplayground.de/\n" "Faites attention, car ceci vérifie le site en entier, celui-ci pouvant " "avoir\n" "plusieurs centaines de milliers d'URL. Utilisez l'option -r pour " "restreindre\n" "la profondeur de la récursion.\n" "\n" "Pour ne pas se connecter aux hôtes mailto:, seulement vérifier leur " "syntaxe.\n" "Tous les autres liens sont vérifiés comme d'habitude :\n" " linkchecker --intern='!^mailto:' --extern-strict-all www.mysite.org\n" "\n" "Pour vérifier un fichier HTML local sur Unix :\n" " linkchecker ../bla.html\n" "\n" "Pour vérifier un fichier HTML local sur Windows :\n" " linkchecker c:\\temp\\test.html\n" "\n" "Vous pouvez ne pas mettre la partie « http:// » de l'URL si le nom de\n" "domaine comme par « www. » :\n" " linkchecker www.myhomepage.de\n" "\n" "Vous pouvez ne pas mettre la partie « ftp:// » de l'URL si le nom de\n" "domaine comme par « ftp. » :\n" " linkchecker -r0 ftp.linux.org\n" #: ../linkcheck/command/arg_parser.py:146 #, fuzzy msgid "" "OUTPUT TYPES\n" "Note that by default only errors and warnings are logged.\n" "You should use the --verbose option to see valid URLs,\n" "and when outputting a sitemap graph format.\n" "\n" "text Standard text output, logging URLs in keyword: argument fashion.\n" "html Log URLs in keyword: argument fashion, formatted as HTML.\n" " Additionally has links to the referenced pages. Invalid URLs have\n" " HTML and CSS syntax check links appended.\n" "csv Log check result in CSV format with one URL per line.\n" "gml Log parent-child relations between linked URLs as a GML sitemap\n" " graph.\n" "dot Log parent-child relations between linked URLs as a DOT sitemap\n" " graph.\n" "gxml Log check result as a GraphXML sitemap graph.\n" "xml Log check result as machine-readable XML.\n" "sql Log check result as SQL script with INSERT commands. An example\n" " script to create the initial SQL table is included as create.sql.\n" "failures\n" " Suitable for cron jobs. Logs the check result into a file\n" " $XDG_DATA_HOME/linkchecker/failures which only contains entries " "with\n" " invalid URLs and the number of times they have failed.\n" "none Logs nothing. Suitable for debugging or checking the exit code.\n" msgstr "" "TYPES DE SORTIE\n" "Notez que seules les erreurs sont journalisées par défaut.\n" "\n" "text Sortie texte standard, journaliser les URL dans des mots clés : mode " "argument.\n" "html Journaliser les URL dans des mots clés : mode argument, formaté en " "HTML.\n" " Contient aussi des liens vers les pages référencées. Les URL " "invalides ont\n" " aussi en plus une vérification syntaxique des liens HTML et CSS.\n" "csv Journaliser le résultat de la vérification au format CSV avec une " "URL par ligne.\n" "gml Journaliser les relations fils/père entre les URL liées dans un " "graphe GML.\n" " Vous devez utiliser l'option --verbose pour avoir un graphe " "complet.\n" "dot Journaliser les relations fils/père entre les URL liées dans un " "graphe DOT.\n" " Vous devez utiliser l'option --verbose pour avoir un graphe " "complet.\n" "xml Journaliser le résultat de la vérification dans un fichier au format " "XML.\n" "sql Journaliser le résultat dans un script SQL avec des commandes " "INSERT.\n" " Un script d'exemple montrant la création de la table SQL initiale " "est inclus : create.sql.\n" "blacklist\n" " Approprié pour les tâches cron. Journaliser le résultat de la " "vérification dans\n" " un fichier ~/.blacklist qui ne contient que les entrées avec des URL " "invalides\n" " et le nombre de fois qu'elles ont échoué.\n" "none Ne rien journaliser du tout. Approprié pour les scripts.\n" #: ../linkcheck/command/arg_parser.py:174 msgid "" "IGNORE WARNINGS\n" "The following warnings are recognized in the 'ignorewarnings' config\n" "file entry:\n" msgstr "" #: ../linkcheck/command/arg_parser.py:212 msgid "General options" msgstr "Options générales" #: ../linkcheck/command/arg_parser.py:219 #, fuzzy, python-format msgid "" "Use FILENAME as configuration file. Per default LinkChecker uses\n" "$XDG_CONFIG_HOME/linkchecker/linkcheckerrc (under Windows\n" "%%HOMEPATH%%\\.config\\linkchecker\\linkcheckerrc)." msgstr "" "Utiliser CONFIGFILE comme fichier de configuration. LinkChecker\n" "recherche d'abord /etc/linkchecker/linkcheckerrc puis ~/.linkchecker/" "linkcheckerrc\n" "(sous Windows \\linkcheckerrc)." #: ../linkcheck/command/arg_parser.py:230 #, fuzzy msgid "" "Generate no more than the given number of threads. Default number\n" "of threads is 10. To disable threading specify a non-positive number." msgstr "" "Ne pas avoir plus de THREADS threads. Le nombre de threads est fixé par " "défaut à 10." #: ../linkcheck/command/arg_parser.py:235 msgid "Print version and exit." msgstr "Afficher la version et quitter." #: ../linkcheck/command/arg_parser.py:241 #, fuzzy msgid "Print available check plugins and exit." msgstr "Afficher la version et quitter." #: ../linkcheck/command/arg_parser.py:246 msgid "Read list of white-space separated URLs to check from stdin." msgstr "" #: ../linkcheck/command/arg_parser.py:250 msgid "Output options" msgstr "Options de sortie" #: ../linkcheck/command/arg_parser.py:257 #, fuzzy, python-format msgid "" "Print debugging output for the given logger.\n" "Available loggers are %(lognamelist)s.\n" "Specifying 'all' is an alias for specifying all available loggers.\n" "The option can be given multiple times to debug with more\n" "than one logger.\n" "\n" "For accurate results, threading will be disabled during debug runs." msgstr "" "Afficher les sorties de débogage pour un enregistreur de journal donné.\n" "Les enregistreurs de journaux disponibles sont %(lognamelist)s.\n" "« all » est un alias pour indiquer que l'on veut tous les enregistreurs\n" "disponibles. Cette option peut être donnée plusieurs fois pour\n" "déboguer avec plus d'un enregistreur de journal.\n" "\n" "Le multithreading est désactivé pendant une exécution en debug\n" "afin de garantir la précision des résultats." #: ../linkcheck/command/arg_parser.py:274 #, fuzzy, python-format msgid "" "Output to a file linkchecker-out.TYPE, $XDG_DATA_HOME/linkchecker/failures " "for\n" "'failures' output, or FILENAME if specified.\n" "The ENCODING specifies the output encoding, the default is that of your\n" "locale.\n" "Valid encodings are listed at https://docs.python.org/library/codecs." "html#standard-encodings.\n" "The FILENAME and ENCODING parts of the 'none' output type will be ignored,\n" "else if the file already exists, it will be overwritten.\n" "You can specify this option more than once. Valid file output types\n" "are %(loggertypes)s. You can specify this option multiple times to output\n" "to more than one file. Default is no file output. Note that you can\n" "suppress all console output with the option '-o none'." msgstr "" "Mettre les sorties dans un fichier linkchecker-out.\n" "TYPE, $HOME/.linkchecker/blacklist pour la sortie « blacklist », ou FILENAME " "si spécifié.\n" "ENCODING spécifie l'encodage de sortie, la valeur par défaut étant " "« iso-8859-15 ».\n" "Les encodages valides sont disponibles sur http://docs.python.org/lib/" "node127.html.\n" "Les parties ENCODING et FILENAME du type de sortie « none »\n" "seront ignorées, sinon, si le fichier existe déjà, il sera écrasé. Vous\n" "pouvez spécifier cette option plus d'une fois. Les TYPEs de fichiers\n" "de sortie valides sont %(loggertypes)s. Vous pouvez spécifier cette\n" "option plusieurs fois pour mettre les sorties dans plus d'un\n" "fichier. Par défaut, il n'y a pas de fichier de sortie. Il faut noter que\n" "vous pouvez supprimer toutes les sorties console avec l'option '-o none'." #: ../linkcheck/command/arg_parser.py:294 msgid "Do not print check status messages." msgstr "Ne pas afficher les messages d'état de la vérification." #: ../linkcheck/command/arg_parser.py:300 msgid "Don't log warnings. Default is to log warnings." msgstr "" #: ../linkcheck/command/arg_parser.py:308 #, fuzzy, python-format msgid "" "Specify output as %(loggertypes)s. Default output type is text.\n" "The ENCODING specifies the output encoding, the default is that of your\n" "locale.\n" "Valid encodings are listed at https://docs.python.org/library/codecs." "html#standard-encodings." msgstr "" "Spécifier la sortie comme %(loggertypes)s. La sortie par défaut est en mode " "texte.\n" "ENCODING spécifie l'encodage de sortie, la valeur par défaut étant " "« iso-8859-15 ».\n" "Les encodages valides sont disponibles sur http://docs.python.org/lib/" "node127.html." #: ../linkcheck/command/arg_parser.py:325 #, fuzzy msgid "" "Quiet operation, an alias for '-o none'.\n" "This is only useful with -F." msgstr "Exécution silencieuse. Utile seulement avec -F." #: ../linkcheck/command/arg_parser.py:336 #, fuzzy msgid "Log all URLs. Default is to log only errors and warnings." msgstr "" "Journaliser toutes les URL vérifiées (implique -w). Par défaut, seules\n" "les URL invalides sont mises dans le journal." #: ../linkcheck/command/arg_parser.py:340 msgid "Checking options" msgstr "Options de vérification" #: ../linkcheck/command/arg_parser.py:346 msgid "" "Read a file with initial cookie data. The cookie data format is\n" "explained below." msgstr "" #: ../linkcheck/command/arg_parser.py:356 msgid "Disable robots.txt checks" msgstr "" #: ../linkcheck/command/arg_parser.py:362 msgid "Check external URLs." msgstr "" #: ../linkcheck/command/arg_parser.py:370 msgid "" "Only check syntax of URLs matching the given regular expression.\n" "This option can be given multiple times." msgstr "" #: ../linkcheck/command/arg_parser.py:380 msgid "" "Check but do not recurse into URLs matching the given regular\n" "expression. This option can be given multiple times." msgstr "" #: ../linkcheck/command/arg_parser.py:390 #, fuzzy msgid "" "Read a password from console and use it for HTTP and FTP authorization.\n" "For FTP the default password is 'anonymous@'. For HTTP there is\n" "no default password. See also -u." msgstr "" "Essayer le mot de passe donné pour l'autorisation HTTP et FTP. Pour FTP,\n" "le mot de passe par défaut est « anonymous@ ». Voir aussi -u." #: ../linkcheck/command/arg_parser.py:402 #, fuzzy msgid "" "Check recursively all links up to given depth. A negative depth\n" "will enable infinite recursion. Default depth is infinite." msgstr "" "Vérifier récursivement tous les liens jusqu'à une profondeur donnée.\n" "Une profondeur négative permet d'avoir une récursion infinie. Par\n" "défaut, la récursion est infinie." #: ../linkcheck/command/arg_parser.py:412 #, fuzzy msgid "Set the timeout for connection attempts in seconds." msgstr "" "Préciser le délai d'expiration pour les attentes de connexion TCP\n" "en secondes. Le délai par défaut est de %d secondes." #: ../linkcheck/command/arg_parser.py:421 #, fuzzy msgid "" "Try the given username for HTTP and FTP authorization.\n" "For FTP the default username is 'anonymous'. For HTTP there is\n" "no default username. See also -p." msgstr "" "Essayer le nom d'utilisateur donné pour l'autorisation HTTP et FTP. Pour " "FTP,\n" "le nom d'utilisateur par défaut est « anonymous ». Voir aussi -p." #: ../linkcheck/command/arg_parser.py:431 msgid "" "Specify the User-Agent string to send to the HTTP server, for example\n" "\"Mozilla/4.0\". The default is \"LinkChecker/X.Y\" where X.Y is the " "current\n" "version of LinkChecker." msgstr "" #: ../linkcheck/logger/html.py:127 ../linkcheck/logger/text.py:112 #, python-format msgid "Start checking at %s" msgstr "Démarrage du contrôle à %s" #: ../linkcheck/logger/html.py:203 ../linkcheck/logger/text.py:165 #, python-format msgid ", line %d" msgstr ", ligne %d" #: ../linkcheck/logger/html.py:205 ../linkcheck/logger/text.py:167 #, python-format msgid ", col %d" msgstr ", col. %d" #: ../linkcheck/logger/html.py:207 ../linkcheck/logger/text.py:169 #, fuzzy, python-format msgid ", page %d" msgstr ", ligne %d" #: ../linkcheck/logger/html.py:246 ../linkcheck/logger/html.py:266 #: ../linkcheck/logger/text.py:185 ../linkcheck/logger/text.py:195 #, python-format msgid "%.3f seconds" msgstr "%.3f secondes" #: ../linkcheck/logger/html.py:311 ../linkcheck/logger/text.py:218 msgid "Valid" msgstr "Valide" #: ../linkcheck/logger/html.py:316 ../linkcheck/logger/text.py:221 msgid "Error" msgstr "Erreur" #: ../linkcheck/logger/html.py:323 msgid "Statistics" msgstr "Statistiques" #: ../linkcheck/logger/html.py:327 ../linkcheck/logger/text.py:300 #, python-format msgid "" "Content types: %(image)d image, %(text)d text, %(video)d video, %(audio)d " "audio, %(application)d application, %(mail)d mail and %(other)d other." msgstr "" #: ../linkcheck/logger/html.py:335 ../linkcheck/logger/text.py:307 #, python-format msgid "URL lengths: min=%(min)d, max=%(max)d, avg=%(avg)d." msgstr "" #: ../linkcheck/logger/html.py:343 ../linkcheck/logger/text.py:315 #, fuzzy msgid "No statistics available since no URLs were checked." msgstr "Aucune statistique disponible puisque aucune URL n'a été vérifiée." #: ../linkcheck/logger/html.py:349 ../linkcheck/logger/text.py:231 msgid "That's it." msgstr "Fin." #: ../linkcheck/logger/html.py:352 #, python-format msgid "%d link checked." msgid_plural "%d links checked." msgstr[0] "%d lien vérifié" msgstr[1] "%d liens vérifiés" #: ../linkcheck/logger/html.py:357 ../linkcheck/logger/text.py:240 #, python-format msgid "%d warning found" msgid_plural "%d warnings found" msgstr[0] "%d avertissement trouvée." msgstr[1] "%d avertissements trouvées." #: ../linkcheck/logger/html.py:362 ../linkcheck/logger/text.py:250 #, python-format msgid " (%d ignored or duplicates not printed)" msgstr "" #: ../linkcheck/logger/html.py:367 ../linkcheck/logger/text.py:255 #, python-format msgid "%d error found" msgid_plural "%d errors found" msgstr[0] "%d erreur trouvée." msgstr[1] "%d erreurs trouvées." #: ../linkcheck/logger/html.py:372 ../linkcheck/logger/text.py:265 #, python-format msgid " (%d duplicates not printed)" msgstr "" #: ../linkcheck/logger/html.py:381 ../linkcheck/logger/text.py:273 #, python-format msgid "There was %(num)d internal error." msgid_plural "There were %(num)d internal errors." msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/html.py:391 ../linkcheck/logger/__init__.py:397 #: ../linkcheck/logger/text.py:282 #, fuzzy, python-format msgid "Stopped checking at %(time)s (%(duration)s)" msgstr "Arrêt du contrôle à %s (%s)" #: ../linkcheck/logger/html.py:401 #, fuzzy, python-format msgid "Read the documentation at %s" msgstr "Récupérez la dernière version sur %s" #: ../linkcheck/logger/html.py:411 #, python-format msgid "Write comments and bugs to %s" msgstr "Écrivez des commentaires et rapports de bogue à %s." #: ../linkcheck/logger/failures.py:47 #, python-format msgid "%(blacklist)s file is deprecated please rename to failures" msgstr "" #: ../linkcheck/logger/failures.py:99 #, python-format msgid "invalid line starting with '%(linestart)s' in %(failures)s" msgstr "" #: ../linkcheck/logger/__init__.py:31 msgid "Real URL" msgstr "URL Réelle" #: ../linkcheck/logger/__init__.py:32 msgid "Cache key" msgstr "Clef du cache" #: ../linkcheck/logger/__init__.py:33 msgid "Result" msgstr "Résultat" #: ../linkcheck/logger/__init__.py:34 msgid "Base" msgstr "Base" #: ../linkcheck/logger/__init__.py:35 msgid "Name" msgstr "Nom" #: ../linkcheck/logger/__init__.py:36 msgid "Parent URL" msgstr "URL parente" #: ../linkcheck/logger/__init__.py:37 msgid "Extern" msgstr "Externe" #: ../linkcheck/logger/__init__.py:38 msgid "Info" msgstr "Info" #: ../linkcheck/logger/__init__.py:39 msgid "Warning" msgstr "Avertissement" #: ../linkcheck/logger/__init__.py:40 #, fuzzy msgid "D/L time" msgstr "Temps D/L" #: ../linkcheck/logger/__init__.py:41 msgid "Size" msgstr "Taille" #: ../linkcheck/logger/__init__.py:42 msgid "Check time" msgstr "Temps de vérification" #: ../linkcheck/logger/__init__.py:43 msgid "URL" msgstr "URL" #: ../linkcheck/logger/__init__.py:44 msgid "Level" msgstr "" #: ../linkcheck/logger/__init__.py:45 msgid "Modified" msgstr "" #: ../linkcheck/logger/__init__.py:275 #, python-format msgid "Happy birthday for LinkChecker, I'm %d years old today!" msgstr "Joyeux anniversaire LinkChecker, j'ai %d ans aujourd'hui !" #: ../linkcheck/logger/__init__.py:381 #, python-format msgid "created by %(app)s at %(time)s" msgstr "créé par %(app)s à %(time)s" #: ../linkcheck/logger/__init__.py:385 ../linkcheck/logger/text.py:105 #, fuzzy, python-format msgid "Read the documentation at %(url)s" msgstr "Récupérez la dernière version sur %(url)s" #: ../linkcheck/logger/__init__.py:388 ../linkcheck/logger/text.py:108 #, python-format msgid "Write comments and bugs to %(url)s" msgstr "Écrivez des commentaires et rapports de bogue à %(url)s" #: ../linkcheck/logger/text.py:65 msgid "Invalid value for wraplength. Using default." msgstr "" #: ../linkcheck/logger/text.py:230 msgid "The check has been interrupted; results are not complete." msgstr "" #: ../linkcheck/logger/text.py:232 #, fuzzy, python-format msgid "%d link" msgid_plural "%d links" msgstr[0] "%d lien vérifié" msgstr[1] "%d liens vérifiés" #: ../linkcheck/logger/text.py:236 #, fuzzy, python-format msgid "in %d URL" msgid_plural "in %d URLs" msgstr[0] "URLs valides" msgstr[1] "URLs valides" #: ../linkcheck/logger/text.py:238 #, fuzzy msgid " checked." msgstr "%d lien vérifié" #: ../linkcheck/logger/text.py:292 msgid "Statistics:" msgstr "Statistiques :" #: ../linkcheck/logger/text.py:295 #, python-format msgid "Downloaded: %s." msgstr "" #: ../linkcheck/__init__.py:77 #, python-format msgid "Link pattern %r strict=%s" msgstr "" #: ../linkcheck/__init__.py:87 #, fuzzy, python-format msgid "invalid regular expression %r: %s" msgstr "Niveau de récursion invalide" #: ../linkcheck/__init__.py:111 msgid "CRITICAL" msgstr "CRITICAL" #: ../linkcheck/__init__.py:112 msgid "ERROR" msgstr "ERROR" #: ../linkcheck/__init__.py:113 msgid "WARN" msgstr "WARN" #: ../linkcheck/__init__.py:114 msgid "WARNING" msgstr "WARNING" #: ../linkcheck/__init__.py:115 msgid "INFO" msgstr "INFO" #: ../linkcheck/__init__.py:116 msgid "DEBUG" msgstr "DEBUG" #: ../linkcheck/__init__.py:117 msgid "NOTSET" msgstr "NOTSET" #: ../linkcheck/strformat.py:165 #, python-format msgid "%(prefix)s%(duration).02f seconds" msgstr "" #: ../linkcheck/strformat.py:170 #, python-format msgid "%d second" msgid_plural "%d seconds" msgstr[0] "%d seconde" msgstr[1] "%d secondes" #: ../linkcheck/strformat.py:171 #, python-format msgid "%d minute" msgid_plural "%d minutes" msgstr[0] "%d minute" msgstr[1] "%d minutes" #: ../linkcheck/strformat.py:172 #, python-format msgid "%d hour" msgid_plural "%d hours" msgstr[0] "%d heure" msgstr[1] "%d heures" #: ../linkcheck/strformat.py:173 #, python-format msgid "%d day" msgid_plural "%d days" msgstr[0] "%d jour" msgstr[1] "%d jours" #: ../linkcheck/strformat.py:174 #, python-format msgid "%d year" msgid_plural "%d years" msgstr[0] "%d année" msgstr[1] "%d années" #: ../linkcheck/strformat.py:245 #, python-format msgid "" "Could not import %(module)s for %(feature)s. Install %(module)s from %(url)s " "to use this feature." msgstr "" #: ../linkcheck/cache/robots_txt.py:77 #, python-format msgid "Relative Sitemap %s in %s discarded" msgstr "" #: ../linkcheck/loader.py:40 #, python-format msgid "WARN: could not load module %s: %s" msgstr "" #: ../linkcheck/loader.py:57 #, fuzzy, python-format msgid "WARN: could not load file %s: %s" msgstr "Impossible d'enregistrer les cookies : %(msg)s." #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:228 #, python-format msgid "%(heading)s:" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:300 #, fuzzy msgid "usage: " msgstr "Usage : %s\n" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:726 #, python-format msgid " (default: %(default)s)" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:780 #, python-format msgid "argument %(argument_name)s: %(message)s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:886 msgid ".__call__() not defined" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1157 msgid "show program's version number and exit" msgstr "afficher le numéro de version du programme et se terminer" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1219 #, fuzzy, python-format msgid "conflicting subparser: %s" msgstr "Options obsolètes" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1223 #, fuzzy, python-format msgid "conflicting subparser alias: %s" msgstr "Options obsolètes" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1258 #, python-format msgid "unknown parser %(parser_name)r (choices: %(choices)s)" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1318 #, python-format msgid "argument \"-\" with mode %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1327 #, python-format msgid "can't open '%(filename)s': %(error)s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1536 #, python-format msgid "cannot merge actions - two groups are named %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1574 msgid "'required' is an invalid argument for positionals" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1596 #, python-format msgid "" "invalid option string %(option)r: must start with a character " "%(prefix_chars)r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1614 #, python-format msgid "dest= is required for options like %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1631 #, python-format msgid "invalid conflict_resolution value: %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1649 #, fuzzy, python-format msgid "conflicting option string: %s" msgid_plural "conflicting option strings: %s" msgstr[0] "Options obsolètes" msgstr[1] "Options obsolètes" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1723 msgid "mutually exclusive arguments must be optional" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1799 #, fuzzy msgid "positional arguments" msgstr "L'option %s nécessite un argument" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1800 #, fuzzy msgid "options" msgstr "Options de sortie" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1815 msgid "show this help message and exit" msgstr "afficher ce message d'aide et se terminer" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1846 msgid "cannot have multiple subparser arguments" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1898 #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2421 #, python-format msgid "unrecognized arguments: %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2001 #, python-format msgid "not allowed with argument %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2043 #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2074 #, python-format msgid "ignored explicit argument %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2181 #, python-format msgid "the following arguments are required: %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2196 #, python-format msgid "one of the arguments %s is required" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2240 msgid "expected one argument" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2241 msgid "expected at most one argument" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2242 msgid "expected at least one argument" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2246 #, python-format msgid "expected %s argument" msgid_plural "expected %s arguments" msgstr[0] "" msgstr[1] "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2303 #, fuzzy, python-format msgid "ambiguous option: %(option)s could match %(matches)s" msgstr "option ambiguë : %s (%s ?)" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2364 #, fuzzy, python-format msgid "unexpected option string: %s" msgstr "Options obsolètes" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2566 #, python-format msgid "%r is not callable" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2582 #, fuzzy, python-format msgid "invalid %(type)s value: %(value)r" msgstr "option %s : valeur %s invalide : %r" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2593 #, fuzzy, python-format msgid "invalid choice: %(value)r (choose from %(choices)s)" msgstr "option %s : choix invalide : %r (choisir dans %s)" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2671 #, fuzzy, python-format msgid "%(prog)s: error: %(message)s\n" msgstr "extern%d : erreur de syntaxe %s\n" #~ msgid "No NNTP server was specified, skipping this URL." #~ msgstr "Aucun serveur NNTP spécifié, l'URL est ignorée." #, fuzzy, python-format #~ msgid "Article number %(num)s found." #~ msgstr "Article numéro %s trouvé." #, fuzzy, python-format #~ msgid "News group %(name)s found." #~ msgstr "Aucun hôte de messagerie trouvé pour %(domain)s." #~ msgid "No newsgroup specified in NNTP URL." #~ msgstr "Aucun newsgroup spécifié dans l'URL NNTP." #, fuzzy, python-format #~ msgid "NNTP server too busy; tried more than %d times." #~ msgstr "Le serveur NNTP est trop chargé ; plus de %d essais effectués." #~ msgid "Host is empty" #~ msgstr "L'hôte est vide." #~ msgid "" #~ "Specify an NNTP server for 'news:...' links. Default is the\n" #~ "environment variable NNTP_SERVER. If no host is given,\n" #~ "only the syntax of the link is checked." #~ msgstr "" #~ "Spécifier un serveur NNTP pour les liens « news: ». Par défaut,\n" #~ "la variable d'environnement NNTP_SERVER est utilisée. Si aucun hôte " #~ "n'est\n" #~ "donné, LinkChecker n'effectue qu'une vérification de la syntaxe du lien." #, fuzzy #~ msgid "optional arguments" #~ msgstr "L'option %s nécessite un argument" #, fuzzy #~ msgid "The URL has been ignored." #~ msgstr "URL %s ignorée." #~ msgid "Using proxy `%(proxy)s'." #~ msgstr "Utilisation du proxy `%(proxy)s'." linkchecker-10.5.0/po/linkchecker.pot000066400000000000000000001275341466565367000175410ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Bastian Kleineidam # This file is distributed under the same license as the LinkChecker package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: LinkChecker\n" "Report-Msgid-Bugs-To: https://github.com/linkchecker/linkchecker\n" "POT-Creation-Date: 2024-08-27 18:47+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: ../linkcheck/director/__init__.py:36 #, python-format msgid "Problem using login URL: %(msg)s." msgstr "" #: ../linkcheck/director/__init__.py:39 #, python-format msgid "Error using login URL: %(msg)s." msgstr "" #: ../linkcheck/director/__init__.py:44 #, python-format msgid "Error starting log output: %(msg)s." msgstr "" #: ../linkcheck/director/__init__.py:60 msgid "" "Could not start a new thread. Check that the current user is allowed to start " "new threads." msgstr "" #: ../linkcheck/director/__init__.py:93 msgid "interrupt; waiting for active threads to finish" msgstr "" #: ../linkcheck/director/__init__.py:94 msgid "another interrupt will exit immediately" msgstr "" #: ../linkcheck/director/__init__.py:110 msgid "user abort; force shutdown" msgstr "" #: ../linkcheck/director/aggregator.py:54 #, python-format msgid "Could not parse cookie file: %s. %s" msgstr "" #: ../linkcheck/director/aggregator.py:188 msgid "These URLs are still active:" msgstr "" #: ../linkcheck/director/aggregator.py:200 #, python-format msgid "" "%(num)d URLs are still active. After a timeout of %(timeout)s the active URLs " "will stop." msgstr "" #: ../linkcheck/director/console.py:38 #, python-format msgid "%2d thread active" msgid_plural "%2d threads active" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:40 #, python-format msgid "%5d link queued" msgid_plural "%5d links queued" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:42 #, python-format msgid "%4d link" msgid_plural "%4d links" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:44 #, python-format msgid "%3d URL" msgid_plural "%3d URLs" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:46 #, python-format msgid "runtime %s" msgstr "" #: ../linkcheck/director/console.py:66 #, python-format msgid "" "********** Oops, I did it again. *************\n" "\n" "You have found an internal error in LinkChecker. Please write a bug report\n" "at %s\n" "and include the following information:\n" "- the URL or file you are testing\n" "- the system information below\n" "\n" "When using the commandline client:\n" "- your commandline arguments and any custom configuration files.\n" "- the output of a debug run with option \"-Dall\"\n" "\n" "Not disclosing some of the information above due to privacy reasons is ok.\n" "I will try to help you nonetheless, but you have to give me something\n" "I can work with ;) .\n" msgstr "" #: ../linkcheck/director/console.py:94 msgid "******** LinkChecker internal error, over and out ********" msgstr "" #: ../linkcheck/director/console.py:140 msgid "System info:" msgstr "" #: ../linkcheck/director/console.py:142 msgid "Released on:" msgstr "" #: ../linkcheck/director/console.py:144 ../linkcheck/command/linkchecker.py:130 #, python-format msgid "Python %(version)s on %(platform)s" msgstr "" #: ../linkcheck/director/console.py:152 msgid "Local time:" msgstr "" #: ../linkcheck/director/console.py:153 msgid "sys.argv:" msgstr "" #: ../linkcheck/director/console.py:158 msgid "released" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:56 msgid "HTML syntax check plugin is broken. Fixes welcome." msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:74 msgid "valid HTML syntax" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:81 #, python-format msgid "HTML syntax check plugin error: %(msg)s " msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:114 msgid "valid CSS syntax" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:121 #, python-format msgid "CSS syntax check plugin error: %(msg)s " msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:132 #, python-format msgid "%(w3type)s validation error at line %(line)s col %(column)s: %(msg)s" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:136 #, python-format msgid "%(w3type)s validation error at line %(line)s: %(msg)s" msgstr "" #: ../linkcheck/plugins/markdowncheck.py:88 #: ../linkcheck/plugins/regexcheck.py:45 #, python-format msgid "Invalid regex pattern %r: %s" msgstr "" #: ../linkcheck/plugins/regexcheck.py:61 #, python-format msgid "Found %(match)r at line %(line)d in link contents." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:70 msgid "certificate did not include \"notAfter\" information" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:73 msgid "SSL verification is disabled; enable the sslverify option" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:85 #, python-format msgid "Invalid SSL certificate \"notAfter\" value %r" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:94 #, python-format msgid "SSL certificate is expired on %(expire)s." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:100 #, python-format msgid "SSL certificate expires on %(expire)s and is only %(valid)s valid." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:104 #, python-format msgid "SSL certificate expires on %(expire)s and is %(valid)s valid." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:118 #: ../linkcheck/configuration/confparse.py:98 #: ../linkcheck/configuration/confparse.py:116 #, python-format msgid "invalid value for %s: %d must not be less than %d" msgstr "" #: ../linkcheck/plugins/locationinfo.py:46 #, python-format msgid "URL is located in %(location)s." msgstr "" #: ../linkcheck/plugins/viruscheck.py:101 msgid "clamd is not ready for stream scanning" msgstr "" #: ../linkcheck/plugins/viruscheck.py:160 msgid "ScannerDaemonOutputFormat must be disabled" msgstr "" #: ../linkcheck/plugins/viruscheck.py:163 msgid "only one of TCPSocket and LocalSocket must be enabled" msgstr "" #: ../linkcheck/plugins/viruscheck.py:193 msgid "one of TCPSocket or LocalSocket must be enabled" msgstr "" #: ../linkcheck/plugins/viruscheck.py:229 msgid "Could not connect to ClamAV daemon." msgstr "" #: ../linkcheck/plugins/anchorcheck.py:70 #, python-format msgid "Anchor `%(name)s' (decoded: `%(decoded)s') not found." msgstr "" #: ../linkcheck/plugins/anchorcheck.py:71 #, python-format msgid "Available anchors: %(anchors)s." msgstr "" #: ../linkcheck/cookies.py:46 msgid "No entries found" msgstr "" #: ../linkcheck/cmdline.py:61 #, python-format msgid "Error: %(msg)s" msgstr "" #: ../linkcheck/cmdline.py:63 #, python-format msgid "Execute '%(program)s -h' for help" msgstr "" #: ../linkcheck/configuration/__init__.py:227 #, python-format msgid "Configuration file %r does not exist." msgstr "" #: ../linkcheck/configuration/__init__.py:229 #, python-format msgid "Configuration file %r is not readable." msgstr "" #: ../linkcheck/configuration/__init__.py:239 msgid "missing user or URL pattern in authentication data." msgstr "" #: ../linkcheck/configuration/__init__.py:274 msgid "activating text logger output." msgstr "" #: ../linkcheck/configuration/__init__.py:285 msgid "no user/password authentication data found for login URL." msgstr "" #: ../linkcheck/configuration/__init__.py:289 msgid "login URL is not a HTTP URL." msgstr "" #: ../linkcheck/configuration/__init__.py:293 msgid "login URL is incomplete." msgstr "" #: ../linkcheck/configuration/__init__.py:296 #, python-format msgid "disabling login URL %(url)s." msgstr "" #: ../linkcheck/configuration/__init__.py:349 #, python-format msgid "could not create plugin directory %(dirname)r: %(errmsg)r" msgstr "" #: ../linkcheck/configuration/__init__.py:397 #, python-format msgid "could not copy initial configuration file %(src)r to %(dst)r: %(errmsg)r" msgstr "" #: ../linkcheck/configuration/confparse.py:62 #, python-format msgid "configuration files %s contain no sections." msgstr "" #: ../linkcheck/configuration/confparse.py:75 #, python-format msgid "Error parsing configuration: %s" msgstr "" #: ../linkcheck/configuration/confparse.py:83 #, python-format msgid "invalid empty value for %s: %s\n" msgstr "" #: ../linkcheck/configuration/confparse.py:103 #: ../linkcheck/configuration/confparse.py:121 #, python-format msgid "invalid value for %s: %d must not be greater than %d" msgstr "" #: ../linkcheck/configuration/confparse.py:136 msgid "" "The blacklist section in linkcheckerrc is deprecated, please rename to " "failures" msgstr "" #: ../linkcheck/configuration/confparse.py:237 #, python-format msgid "missing auth part in entry %(val)r" msgstr "" #: ../linkcheck/configuration/confparse.py:247 #, python-format msgid "invalid login URL `%s'. Only HTTP and HTTPS URLs are supported." msgstr "" #: ../linkcheck/configuration/confparse.py:276 #, python-format msgid "" "The configuration file %s contains password information (in section [%s] and " "options %s) and the file is readable by others. Please make the file only " "readable by you." msgstr "" #: ../linkcheck/configuration/confparse.py:285 #, python-format msgid "For example execute 'chmod go-rw %s'." msgstr "" #: ../linkcheck/configuration/confparse.py:290 #, python-format msgid "See %(url)s for more info on setting file permissions." msgstr "" #: ../linkcheck/lc_cgi.py:215 #, python-format msgid "could not set locale %r: %s" msgstr "" #: ../linkcheck/lc_cgi.py:217 #, python-format msgid "unsupported language %r" msgstr "" #: ../linkcheck/lc_cgi.py:222 msgid "empty url was given" msgstr "" #: ../linkcheck/lc_cgi.py:224 #, python-format msgid "disallowed url %r was given" msgstr "" #: ../linkcheck/lc_cgi.py:226 msgid "no url was given" msgstr "" #: ../linkcheck/lc_cgi.py:231 #, python-format msgid "invalid recursion level %r" msgstr "" #: ../linkcheck/lc_cgi.py:237 #, python-format msgid "invalid %s option %r" msgstr "" #: ../linkcheck/lc_cgi.py:264 #, python-format msgid "" "\n" "\n" "\n" "LinkChecker Online Error\n" "\n" "
\n" "Error: %s
\n" "The LinkChecker Online script has encountered an error. Please ensure\n" "that your provided URL link begins with http:// and\n" "contains only these characters: A-Za-z0-9./_~-

\n" "Errors are logged.\n" "
\n" "\n" "" msgstr "" #: ../linkcheck/checker/fileurl.py:142 #, python-format msgid "Could not get current working directory: %(msg)s" msgstr "" #: ../linkcheck/checker/fileurl.py:175 ../linkcheck/checker/fileurl.py:339 msgid "Added trailing slash to directory." msgstr "" #: ../linkcheck/checker/fileurl.py:198 ../linkcheck/checker/fileurl.py:352 msgid "" "local files are only checked without parent URL or when the parent URL is " "also a file" msgstr "" #: ../linkcheck/checker/fileurl.py:203 ../linkcheck/checker/fileurl.py:367 msgid "directory" msgstr "" #: ../linkcheck/checker/fileurl.py:222 #, python-format msgid "" "The URL path %(path)r is not the same as the system path %(realpath)r. You " "should always use the system path in URLs." msgstr "" #: ../linkcheck/checker/fileurl.py:360 #, python-format msgid "" "URL `%s' is a directory with an anchor. When checking local files AnchorCheck " "does not support anchors for directories." msgstr "" #: ../linkcheck/checker/itmsservicesurl.py:31 msgid "Missing required url parameter" msgstr "" #: ../linkcheck/checker/urlbase.py:79 #, python-format msgid "URL has unparsable domain name: %(name)s" msgstr "" #: ../linkcheck/checker/urlbase.py:163 msgid "The URL is outside of the domain filter, checked only syntax." msgstr "" #: ../linkcheck/checker/urlbase.py:166 msgid "filtered" msgstr "" #: ../linkcheck/checker/urlbase.py:216 #, python-format msgid "Leading or trailing whitespace in URL `%(url)s'." msgstr "" #: ../linkcheck/checker/urlbase.py:340 #, python-format msgid "The URL with content type %r is not parseable." msgstr "" #: ../linkcheck/checker/urlbase.py:445 msgid "URL is empty" msgstr "" #: ../linkcheck/checker/urlbase.py:460 #, python-format msgid "Effective URL %(url)r." msgstr "" #: ../linkcheck/checker/urlbase.py:467 #, python-format msgid "URL length %(len)d is longer than %(max)d." msgstr "" #: ../linkcheck/checker/urlbase.py:517 ../linkcheck/checker/urlbase.py:523 #, python-format msgid "URL host %(host)r has invalid port" msgstr "" #: ../linkcheck/checker/urlbase.py:530 msgid "URL has empty hostname" msgstr "" #: ../linkcheck/checker/urlbase.py:555 #, python-format msgid "URL %(url)s has obfuscated IP address %(ip)s" msgstr "" #: ../linkcheck/checker/urlbase.py:591 msgid "Hostname not found" msgstr "" #: ../linkcheck/checker/urlbase.py:594 #, python-format msgid "Bad hostname %(host)r: %(msg)s" msgstr "" #: ../linkcheck/checker/urlbase.py:614 #, python-format msgid "could not get content: %(msg)s" msgstr "" #: ../linkcheck/checker/urlbase.py:669 #, python-format msgid "Content size %(size)s is larger than %(maxbytes)s." msgstr "" #: ../linkcheck/checker/urlbase.py:763 msgid "Content size is zero." msgstr "" #: ../linkcheck/checker/urlbase.py:800 ../linkcheck/checker/httpurl.py:348 msgid "File size too large" msgstr "" #: ../linkcheck/checker/urlbase.py:881 #, python-format msgid "URL has unparsable domain name: %(domain)s" msgstr "" #: ../linkcheck/checker/unknownurl.py:32 #, python-format msgid "%(scheme)s URL ignored." msgstr "" #: ../linkcheck/checker/unknownurl.py:34 msgid "ignored" msgstr "" #: ../linkcheck/checker/unknownurl.py:36 msgid "URL is unrecognized or has invalid syntax" msgstr "" #: ../linkcheck/checker/mailtourl.py:88 #, python-format msgid "No mail addresses or email subject found in `%(url)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:132 #, python-format msgid "Error parsing CGI values: %s" msgstr "" #: ../linkcheck/checker/mailtourl.py:158 #, python-format msgid "" "Mail address `%(addr)s' too long. Allowed 256 chars, was %(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:168 #, python-format msgid "Missing `@' in mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:177 #, python-format msgid "Missing local part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:184 #, python-format msgid "Missing domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:192 #, python-format msgid "" "Local part of mail address `%(addr)s' too long. Allowed 64 chars, was " "%(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:203 #, python-format msgid "" "Domain part of mail address `%(addr)s' too long. Allowed 255 chars, was " "%(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:218 #, python-format msgid "Unquoted double quote or backslash in mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:227 #, python-format msgid "Local part of mail address `%(addr)s' may not start with a dot." msgstr "" #: ../linkcheck/checker/mailtourl.py:235 #, python-format msgid "Local part of mail address `%(addr)s' may not end with a dot." msgstr "" #: ../linkcheck/checker/mailtourl.py:243 #, python-format msgid "Local part of mail address `%(addr)s' may not contain two dots." msgstr "" #: ../linkcheck/checker/mailtourl.py:253 #, python-format msgid "" "Local part of mail address `%(addr)s' contains unquoted character `%(char)s." msgstr "" #: ../linkcheck/checker/mailtourl.py:271 #, python-format msgid "Domain part of mail address `%(addr)s' has invalid IP." msgstr "" #: ../linkcheck/checker/mailtourl.py:281 #, python-format msgid "Invalid domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:289 #, python-format msgid "Invalid top level domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:327 #, python-format msgid "No MX mail host for %(domain)s found." msgstr "" #: ../linkcheck/checker/mailtourl.py:336 #, python-format msgid "No host for %(domain)s found." msgstr "" #: ../linkcheck/checker/mailtourl.py:353 #, python-format msgid "Got invalid DNS answer %(answer)s for %(domain)s." msgstr "" #: ../linkcheck/checker/mailtourl.py:366 msgid "Valid mail address syntax" msgstr "" #: ../linkcheck/checker/const.py:99 msgid "The effective URL is different from the original." msgstr "" #: ../linkcheck/checker/const.py:100 msgid "Could not get the content of the URL." msgstr "" #: ../linkcheck/checker/const.py:101 msgid "The URL content size is too large." msgstr "" #: ../linkcheck/checker/const.py:102 msgid "The URL content size is zero." msgstr "" #: ../linkcheck/checker/const.py:103 msgid "The URL content type is not parseable." msgstr "" #: ../linkcheck/checker/const.py:104 msgid "The URL is longer than the recommended size." msgstr "" #: ../linkcheck/checker/const.py:105 msgid "The URL contains leading or trailing whitespace." msgstr "" #: ../linkcheck/checker/const.py:106 msgid "The file: URL is missing a trailing slash." msgstr "" #: ../linkcheck/checker/const.py:108 msgid "The file: path is not the same as the system specific path." msgstr "" #: ../linkcheck/checker/const.py:111 msgid "A local directory with an anchor, not supported by AnchorCheck." msgstr "" #: ../linkcheck/checker/const.py:112 msgid "The ftp: URL is missing a trailing slash." msgstr "" #: ../linkcheck/checker/const.py:113 msgid "The URL had no content." msgstr "" #: ../linkcheck/checker/const.py:114 msgid "An error occurred while storing a cookie." msgstr "" #: ../linkcheck/checker/const.py:115 msgid "The URL request was rate limited." msgstr "" #: ../linkcheck/checker/const.py:116 msgid "Redirected to a different URL." msgstr "" #: ../linkcheck/checker/const.py:117 msgid "The mail MX host could not be found." msgstr "" #: ../linkcheck/checker/const.py:118 msgid "The IP is obfuscated." msgstr "" #: ../linkcheck/checker/const.py:119 msgid "XML could not be parsed." msgstr "" #: ../linkcheck/checker/ftpurl.py:75 msgid "Got no answer from FTP server" msgstr "" #: ../linkcheck/checker/ftpurl.py:78 #, python-format msgid "Remote host has closed connection: %(msg)s" msgstr "" #: ../linkcheck/checker/ftpurl.py:124 msgid "Missing trailing directory slash in ftp url." msgstr "" #: ../linkcheck/checker/ftpurl.py:188 msgid "FTP file size too large" msgstr "" #: ../linkcheck/checker/httpurl.py:138 msgid "Access denied by robots.txt, checked only syntax." msgstr "" #: ../linkcheck/checker/httpurl.py:139 msgid "syntax OK" msgstr "" #: ../linkcheck/checker/httpurl.py:283 #, python-format msgid "Redirected to `%(url)s' status: %(code)d %(reason)s." msgstr "" #: ../linkcheck/checker/httpurl.py:336 msgid "OK" msgstr "" #: ../linkcheck/checker/dnsurl.py:46 #, python-format msgid "%(host)s resolved to IPs %(ips)s" msgstr "" #: ../linkcheck/checker/dnsurl.py:48 #, python-format msgid "%(host)r could not be resolved" msgstr "" #: ../linkcheck/command/setup_config.py:49 msgid "Running with python -O disables debugging." msgstr "" #: ../linkcheck/command/setup_config.py:81 #, python-format msgid "blacklist is deprecated for option %(option)s, using failures instead" msgstr "" #: ../linkcheck/command/setup_config.py:87 #: ../linkcheck/command/setup_config.py:133 #, python-format msgid "Unknown logger type %(type)r in %(output)r for option %(option)s" msgstr "" #: ../linkcheck/command/setup_config.py:94 #: ../linkcheck/command/setup_config.py:144 #, python-format msgid "Unknown encoding %(encoding)r in %(output)r for option %(option)s" msgstr "" #: ../linkcheck/command/setup_config.py:127 #, python-format msgid "" "blacklist logger is deprecated for option %(option)s, using failures instead" msgstr "" #: ../linkcheck/command/setup_config.py:159 #, python-format msgid "Enter LinkChecker HTTP/FTP password for user %(user)s:" msgstr "" #: ../linkcheck/command/setup_config.py:163 msgid "Enter LinkChecker HTTP/FTP password:" msgstr "" #: ../linkcheck/command/setup_config.py:181 #, python-format msgid "Illegal argument %(arg)r for option %(option)s" msgstr "" #: ../linkcheck/command/setup_config.py:198 #, python-format msgid "Enter LinkChecker password for user %(user)s at %(strpattern)s:" msgstr "" #: ../linkcheck/command/setup_config.py:207 #, python-format msgid "Cookie file %s does not exist." msgstr "" #: ../linkcheck/command/setup_config.py:210 #, python-format msgid "Could not read cookie file %s" msgstr "" #: ../linkcheck/command/linkchecker.py:50 msgid "Running as root user; dropping privileges by changing user to nobody." msgstr "" #: ../linkcheck/command/linkchecker.py:124 #, python-format msgid "Invalid debug level %(level)r" msgstr "" #: ../linkcheck/command/linkchecker.py:140 #, python-format msgid "Config file %s does not exist." msgstr "" #: ../linkcheck/command/linkchecker.py:143 #, python-format msgid "Could not read config file %s." msgstr "" #: ../linkcheck/command/linkchecker.py:176 msgid "no files or URLs given" msgstr "" #: ../linkcheck/command/linkchecker.py:184 #, python-format msgid "" "Overwrite profiling file %(file)r?\n" "Press Ctrl-C to cancel, RETURN to continue." msgstr "" #: ../linkcheck/command/linkchecker.py:192 msgid "Canceled." msgstr "" #: ../linkcheck/command/linkchecker.py:199 msgid "" "The `yappi' Python module is not installed, therefore the --profile option is " "disabled." msgstr "" #: ../linkcheck/command/linkchecker.py:218 msgid "Dumping memory statistics..." msgstr "" #: ../linkcheck/command/linkchecker.py:220 #, python-format msgid "The memory dump has been written to `%(filename)s'." msgstr "" #: ../linkcheck/command/arg_parser.py:28 msgid "" "NOTES\n" " o URLs on the command line starting with \"ftp.\" are treated like\n" " \"ftp://ftp.\", URLs starting with \"www.\" are treated like \"http://www." "\".\n" " You can also give local files as arguments.\n" " o If you have your system configured to automatically establish a\n" " connection to the internet (e.g. with diald), it will connect when\n" " checking links not pointing to your local system.\n" " See the --ignore-url option on how to prevent this.\n" " o Javascript links are currently ignored.\n" " o If your platform does not support threading, LinkChecker disables it\n" " automatically.\n" " o You can supply multiple user/password pairs in a configuration file.\n" msgstr "" #: ../linkcheck/command/arg_parser.py:44 msgid "" "PROXY SUPPORT\n" "To use a proxy on Unix or Windows set $http_proxy or $https_proxy\n" "to the proxy URL. The URL should be of the form\n" "\"http://[:@][:]\".\n" "LinkChecker also detects manual proxy settings of Internet Explorer under\n" "Windows systems. On a Mac use the Internet Config to select a proxy.\n" "\n" "LinkChecker honors the $no_proxy environment variable. It can be a list\n" "of domain names for which no proxy will be used.\n" "\n" "Setting a HTTP proxy on Unix for example looks like this:\n" "\n" " export http_proxy=\"http://proxy.example.com:8080\"\n" "\n" "Proxy authentication is also supported:\n" "\n" " export http_proxy=\"http://user1:mypass@proxy.example.org:8081\"\n" "\n" "Setting a proxy on the Windows command prompt:\n" "\n" " set http_proxy=http://proxy.example.com:8080\n" "\n" msgstr "" #: ../linkcheck/command/arg_parser.py:70 msgid "" "REGULAR EXPRESSIONS\n" "Only Python regular expressions are accepted by LinkChecker.\n" "See https://docs.python.org/howto/regex.html for an introduction in\n" "regular expressions.\n" "\n" "The only addition is that a leading exclamation mark negates\n" "the regular expression.\n" msgstr "" #: ../linkcheck/command/arg_parser.py:81 msgid "" "COOKIE FILES\n" "A cookie file contains standard RFC 805 header data with the following\n" "possible names:\n" "Scheme (optional)\n" " Sets the scheme the cookies are valid for; default scheme is 'http'.\n" "Host (required)\n" " Sets the domain the cookies are valid for.\n" "Path (optional)\n" " Gives the path the cookies are value for; default path is '/'.\n" "Set-cookie (optional)\n" " Set cookie name/value. Can be given more than once.\n" "\n" "Multiple entries are separated by a blank line.\n" "\n" "The example below will send two cookies to all URLs starting with\n" "'http://example.org/hello/' and one to all URLs starting\n" "with 'https://example.com/':\n" "\n" "Host: example.org\n" "Path: /hello\n" "Set-cookie: ID=\"smee\"\n" "Set-cookie: spam=\"egg\"\n" "\n" "Scheme: https\n" "Host: example.com\n" "Set-cookie: baggage=\"elitist\"; comment=\"hologram\"\n" msgstr "" #: ../linkcheck/command/arg_parser.py:111 msgid "" "RETURN VALUE\n" "The return value is non-zero when\n" " o invalid links were found or\n" " o warnings were found warnings are enabled\n" " o a program error occurred\n" msgstr "" #: ../linkcheck/command/arg_parser.py:120 msgid "" "EXAMPLES\n" "The most common use checks the given domain recursively, plus any\n" "single URL pointing outside of the domain:\n" " linkchecker http://www.example.org/\n" "Beware that this checks the whole site which can have several hundred\n" "thousands URLs. Use the -r option to restrict the recursion depth.\n" "\n" "Don't connect to mailto: hosts, only check their URL syntax. All other\n" "links are checked as usual:\n" " linkchecker --ignore-url=^mailto: www.example.org\n" "\n" "Checking local HTML files on Unix:\n" " linkchecker ../bla.html subdir/blubber.html\n" "\n" "Checking a local HTML file on Windows:\n" " linkchecker c:\\temp\\test.html\n" "\n" "You can skip the \"http://\" url part if the domain starts with \"www.\":\n" " linkchecker www.example.de\n" "\n" "You can skip the \"ftp://\" url part if the domain starts with \"ftp.\":\n" " linkchecker -r0 ftp.example.org\n" msgstr "" #: ../linkcheck/command/arg_parser.py:146 msgid "" "OUTPUT TYPES\n" "Note that by default only errors and warnings are logged.\n" "You should use the --verbose option to see valid URLs,\n" "and when outputting a sitemap graph format.\n" "\n" "text Standard text output, logging URLs in keyword: argument fashion.\n" "html Log URLs in keyword: argument fashion, formatted as HTML.\n" " Additionally has links to the referenced pages. Invalid URLs have\n" " HTML and CSS syntax check links appended.\n" "csv Log check result in CSV format with one URL per line.\n" "gml Log parent-child relations between linked URLs as a GML sitemap\n" " graph.\n" "dot Log parent-child relations between linked URLs as a DOT sitemap\n" " graph.\n" "gxml Log check result as a GraphXML sitemap graph.\n" "xml Log check result as machine-readable XML.\n" "sql Log check result as SQL script with INSERT commands. An example\n" " script to create the initial SQL table is included as create.sql.\n" "failures\n" " Suitable for cron jobs. Logs the check result into a file\n" " $XDG_DATA_HOME/linkchecker/failures which only contains entries with\n" " invalid URLs and the number of times they have failed.\n" "none Logs nothing. Suitable for debugging or checking the exit code.\n" msgstr "" #: ../linkcheck/command/arg_parser.py:174 msgid "" "IGNORE WARNINGS\n" "The following warnings are recognized in the 'ignorewarnings' config\n" "file entry:\n" msgstr "" #: ../linkcheck/command/arg_parser.py:212 msgid "General options" msgstr "" #: ../linkcheck/command/arg_parser.py:219 #, python-format msgid "" "Use FILENAME as configuration file. Per default LinkChecker uses\n" "$XDG_CONFIG_HOME/linkchecker/linkcheckerrc (under Windows\n" "%%HOMEPATH%%\\.config\\linkchecker\\linkcheckerrc)." msgstr "" #: ../linkcheck/command/arg_parser.py:230 msgid "" "Generate no more than the given number of threads. Default number\n" "of threads is 10. To disable threading specify a non-positive number." msgstr "" #: ../linkcheck/command/arg_parser.py:235 msgid "Print version and exit." msgstr "" #: ../linkcheck/command/arg_parser.py:241 msgid "Print available check plugins and exit." msgstr "" #: ../linkcheck/command/arg_parser.py:246 msgid "Read list of white-space separated URLs to check from stdin." msgstr "" #: ../linkcheck/command/arg_parser.py:250 msgid "Output options" msgstr "" #: ../linkcheck/command/arg_parser.py:257 #, python-format msgid "" "Print debugging output for the given logger.\n" "Available loggers are %(lognamelist)s.\n" "Specifying 'all' is an alias for specifying all available loggers.\n" "The option can be given multiple times to debug with more\n" "than one logger.\n" "\n" "For accurate results, threading will be disabled during debug runs." msgstr "" #: ../linkcheck/command/arg_parser.py:274 #, python-format msgid "" "Output to a file linkchecker-out.TYPE, $XDG_DATA_HOME/linkchecker/failures " "for\n" "'failures' output, or FILENAME if specified.\n" "The ENCODING specifies the output encoding, the default is that of your\n" "locale.\n" "Valid encodings are listed at https://docs.python.org/library/codecs." "html#standard-encodings.\n" "The FILENAME and ENCODING parts of the 'none' output type will be ignored,\n" "else if the file already exists, it will be overwritten.\n" "You can specify this option more than once. Valid file output types\n" "are %(loggertypes)s. You can specify this option multiple times to output\n" "to more than one file. Default is no file output. Note that you can\n" "suppress all console output with the option '-o none'." msgstr "" #: ../linkcheck/command/arg_parser.py:294 msgid "Do not print check status messages." msgstr "" #: ../linkcheck/command/arg_parser.py:300 msgid "Don't log warnings. Default is to log warnings." msgstr "" #: ../linkcheck/command/arg_parser.py:308 #, python-format msgid "" "Specify output as %(loggertypes)s. Default output type is text.\n" "The ENCODING specifies the output encoding, the default is that of your\n" "locale.\n" "Valid encodings are listed at https://docs.python.org/library/codecs." "html#standard-encodings." msgstr "" #: ../linkcheck/command/arg_parser.py:325 msgid "" "Quiet operation, an alias for '-o none'.\n" "This is only useful with -F." msgstr "" #: ../linkcheck/command/arg_parser.py:336 msgid "Log all URLs. Default is to log only errors and warnings." msgstr "" #: ../linkcheck/command/arg_parser.py:340 msgid "Checking options" msgstr "" #: ../linkcheck/command/arg_parser.py:346 msgid "" "Read a file with initial cookie data. The cookie data format is\n" "explained below." msgstr "" #: ../linkcheck/command/arg_parser.py:356 msgid "Disable robots.txt checks" msgstr "" #: ../linkcheck/command/arg_parser.py:362 msgid "Check external URLs." msgstr "" #: ../linkcheck/command/arg_parser.py:370 msgid "" "Only check syntax of URLs matching the given regular expression.\n" "This option can be given multiple times." msgstr "" #: ../linkcheck/command/arg_parser.py:380 msgid "" "Check but do not recurse into URLs matching the given regular\n" "expression. This option can be given multiple times." msgstr "" #: ../linkcheck/command/arg_parser.py:390 msgid "" "Read a password from console and use it for HTTP and FTP authorization.\n" "For FTP the default password is 'anonymous@'. For HTTP there is\n" "no default password. See also -u." msgstr "" #: ../linkcheck/command/arg_parser.py:402 msgid "" "Check recursively all links up to given depth. A negative depth\n" "will enable infinite recursion. Default depth is infinite." msgstr "" #: ../linkcheck/command/arg_parser.py:412 msgid "Set the timeout for connection attempts in seconds." msgstr "" #: ../linkcheck/command/arg_parser.py:421 msgid "" "Try the given username for HTTP and FTP authorization.\n" "For FTP the default username is 'anonymous'. For HTTP there is\n" "no default username. See also -p." msgstr "" #: ../linkcheck/command/arg_parser.py:431 msgid "" "Specify the User-Agent string to send to the HTTP server, for example\n" "\"Mozilla/4.0\". The default is \"LinkChecker/X.Y\" where X.Y is the current\n" "version of LinkChecker." msgstr "" #: ../linkcheck/logger/html.py:127 ../linkcheck/logger/text.py:112 #, python-format msgid "Start checking at %s" msgstr "" #: ../linkcheck/logger/html.py:203 ../linkcheck/logger/text.py:165 #, python-format msgid ", line %d" msgstr "" #: ../linkcheck/logger/html.py:205 ../linkcheck/logger/text.py:167 #, python-format msgid ", col %d" msgstr "" #: ../linkcheck/logger/html.py:207 ../linkcheck/logger/text.py:169 #, python-format msgid ", page %d" msgstr "" #: ../linkcheck/logger/html.py:246 ../linkcheck/logger/html.py:266 #: ../linkcheck/logger/text.py:185 ../linkcheck/logger/text.py:195 #, python-format msgid "%.3f seconds" msgstr "" #: ../linkcheck/logger/html.py:311 ../linkcheck/logger/text.py:218 msgid "Valid" msgstr "" #: ../linkcheck/logger/html.py:316 ../linkcheck/logger/text.py:221 msgid "Error" msgstr "" #: ../linkcheck/logger/html.py:323 msgid "Statistics" msgstr "" #: ../linkcheck/logger/html.py:327 ../linkcheck/logger/text.py:300 #, python-format msgid "" "Content types: %(image)d image, %(text)d text, %(video)d video, %(audio)d " "audio, %(application)d application, %(mail)d mail and %(other)d other." msgstr "" #: ../linkcheck/logger/html.py:335 ../linkcheck/logger/text.py:307 #, python-format msgid "URL lengths: min=%(min)d, max=%(max)d, avg=%(avg)d." msgstr "" #: ../linkcheck/logger/html.py:343 ../linkcheck/logger/text.py:315 msgid "No statistics available since no URLs were checked." msgstr "" #: ../linkcheck/logger/html.py:349 ../linkcheck/logger/text.py:231 msgid "That's it." msgstr "" #: ../linkcheck/logger/html.py:352 #, python-format msgid "%d link checked." msgid_plural "%d links checked." msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/html.py:357 ../linkcheck/logger/text.py:240 #, python-format msgid "%d warning found" msgid_plural "%d warnings found" msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/html.py:362 ../linkcheck/logger/text.py:250 #, python-format msgid " (%d ignored or duplicates not printed)" msgstr "" #: ../linkcheck/logger/html.py:367 ../linkcheck/logger/text.py:255 #, python-format msgid "%d error found" msgid_plural "%d errors found" msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/html.py:372 ../linkcheck/logger/text.py:265 #, python-format msgid " (%d duplicates not printed)" msgstr "" #: ../linkcheck/logger/html.py:381 ../linkcheck/logger/text.py:273 #, python-format msgid "There was %(num)d internal error." msgid_plural "There were %(num)d internal errors." msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/html.py:391 ../linkcheck/logger/__init__.py:397 #: ../linkcheck/logger/text.py:282 #, python-format msgid "Stopped checking at %(time)s (%(duration)s)" msgstr "" #: ../linkcheck/logger/html.py:401 #, python-format msgid "Read the documentation at %s" msgstr "" #: ../linkcheck/logger/html.py:411 #, python-format msgid "Write comments and bugs to %s" msgstr "" #: ../linkcheck/logger/failures.py:47 #, python-format msgid "%(blacklist)s file is deprecated please rename to failures" msgstr "" #: ../linkcheck/logger/failures.py:99 #, python-format msgid "invalid line starting with '%(linestart)s' in %(failures)s" msgstr "" #: ../linkcheck/logger/__init__.py:31 msgid "Real URL" msgstr "" #: ../linkcheck/logger/__init__.py:32 msgid "Cache key" msgstr "" #: ../linkcheck/logger/__init__.py:33 msgid "Result" msgstr "" #: ../linkcheck/logger/__init__.py:34 msgid "Base" msgstr "" #: ../linkcheck/logger/__init__.py:35 msgid "Name" msgstr "" #: ../linkcheck/logger/__init__.py:36 msgid "Parent URL" msgstr "" #: ../linkcheck/logger/__init__.py:37 msgid "Extern" msgstr "" #: ../linkcheck/logger/__init__.py:38 msgid "Info" msgstr "" #: ../linkcheck/logger/__init__.py:39 msgid "Warning" msgstr "" #: ../linkcheck/logger/__init__.py:40 msgid "D/L time" msgstr "" #: ../linkcheck/logger/__init__.py:41 msgid "Size" msgstr "" #: ../linkcheck/logger/__init__.py:42 msgid "Check time" msgstr "" #: ../linkcheck/logger/__init__.py:43 msgid "URL" msgstr "" #: ../linkcheck/logger/__init__.py:44 msgid "Level" msgstr "" #: ../linkcheck/logger/__init__.py:45 msgid "Modified" msgstr "" #: ../linkcheck/logger/__init__.py:275 #, python-format msgid "Happy birthday for LinkChecker, I'm %d years old today!" msgstr "" #: ../linkcheck/logger/__init__.py:381 #, python-format msgid "created by %(app)s at %(time)s" msgstr "" #: ../linkcheck/logger/__init__.py:385 ../linkcheck/logger/text.py:105 #, python-format msgid "Read the documentation at %(url)s" msgstr "" #: ../linkcheck/logger/__init__.py:388 ../linkcheck/logger/text.py:108 #, python-format msgid "Write comments and bugs to %(url)s" msgstr "" #: ../linkcheck/logger/text.py:65 msgid "Invalid value for wraplength. Using default." msgstr "" #: ../linkcheck/logger/text.py:230 msgid "The check has been interrupted; results are not complete." msgstr "" #: ../linkcheck/logger/text.py:232 #, python-format msgid "%d link" msgid_plural "%d links" msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/text.py:236 #, python-format msgid "in %d URL" msgid_plural "in %d URLs" msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/text.py:238 msgid " checked." msgstr "" #: ../linkcheck/logger/text.py:292 msgid "Statistics:" msgstr "" #: ../linkcheck/logger/text.py:295 #, python-format msgid "Downloaded: %s." msgstr "" #: ../linkcheck/__init__.py:77 #, python-format msgid "Link pattern %r strict=%s" msgstr "" #: ../linkcheck/__init__.py:87 #, python-format msgid "invalid regular expression %r: %s" msgstr "" #: ../linkcheck/__init__.py:111 msgid "CRITICAL" msgstr "" #: ../linkcheck/__init__.py:112 msgid "ERROR" msgstr "" #: ../linkcheck/__init__.py:113 msgid "WARN" msgstr "" #: ../linkcheck/__init__.py:114 msgid "WARNING" msgstr "" #: ../linkcheck/__init__.py:115 msgid "INFO" msgstr "" #: ../linkcheck/__init__.py:116 msgid "DEBUG" msgstr "" #: ../linkcheck/__init__.py:117 msgid "NOTSET" msgstr "" #: ../linkcheck/strformat.py:165 #, python-format msgid "%(prefix)s%(duration).02f seconds" msgstr "" #: ../linkcheck/strformat.py:170 #, python-format msgid "%d second" msgid_plural "%d seconds" msgstr[0] "" msgstr[1] "" #: ../linkcheck/strformat.py:171 #, python-format msgid "%d minute" msgid_plural "%d minutes" msgstr[0] "" msgstr[1] "" #: ../linkcheck/strformat.py:172 #, python-format msgid "%d hour" msgid_plural "%d hours" msgstr[0] "" msgstr[1] "" #: ../linkcheck/strformat.py:173 #, python-format msgid "%d day" msgid_plural "%d days" msgstr[0] "" msgstr[1] "" #: ../linkcheck/strformat.py:174 #, python-format msgid "%d year" msgid_plural "%d years" msgstr[0] "" msgstr[1] "" #: ../linkcheck/strformat.py:245 #, python-format msgid "" "Could not import %(module)s for %(feature)s. Install %(module)s from %(url)s " "to use this feature." msgstr "" #: ../linkcheck/cache/robots_txt.py:77 #, python-format msgid "Relative Sitemap %s in %s discarded" msgstr "" #: ../linkcheck/loader.py:40 #, python-format msgid "WARN: could not load module %s: %s" msgstr "" #: ../linkcheck/loader.py:57 #, python-format msgid "WARN: could not load file %s: %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:228 #, python-format msgid "%(heading)s:" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:300 msgid "usage: " msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:726 #, python-format msgid " (default: %(default)s)" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:780 #, python-format msgid "argument %(argument_name)s: %(message)s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:886 msgid ".__call__() not defined" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1157 msgid "show program's version number and exit" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1219 #, python-format msgid "conflicting subparser: %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1223 #, python-format msgid "conflicting subparser alias: %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1258 #, python-format msgid "unknown parser %(parser_name)r (choices: %(choices)s)" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1318 #, python-format msgid "argument \"-\" with mode %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1327 #, python-format msgid "can't open '%(filename)s': %(error)s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1536 #, python-format msgid "cannot merge actions - two groups are named %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1574 msgid "'required' is an invalid argument for positionals" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1596 #, python-format msgid "" "invalid option string %(option)r: must start with a character %(prefix_chars)r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1614 #, python-format msgid "dest= is required for options like %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1631 #, python-format msgid "invalid conflict_resolution value: %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1649 #, python-format msgid "conflicting option string: %s" msgid_plural "conflicting option strings: %s" msgstr[0] "" msgstr[1] "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1723 msgid "mutually exclusive arguments must be optional" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1799 msgid "positional arguments" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1800 msgid "options" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1815 msgid "show this help message and exit" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1846 msgid "cannot have multiple subparser arguments" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1898 #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2421 #, python-format msgid "unrecognized arguments: %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2001 #, python-format msgid "not allowed with argument %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2043 #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2074 #, python-format msgid "ignored explicit argument %r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2181 #, python-format msgid "the following arguments are required: %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2196 #, python-format msgid "one of the arguments %s is required" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2240 msgid "expected one argument" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2241 msgid "expected at most one argument" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2242 msgid "expected at least one argument" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2246 #, python-format msgid "expected %s argument" msgid_plural "expected %s arguments" msgstr[0] "" msgstr[1] "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2303 #, python-format msgid "ambiguous option: %(option)s could match %(matches)s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2364 #, python-format msgid "unexpected option string: %s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2566 #, python-format msgid "%r is not callable" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2582 #, python-format msgid "invalid %(type)s value: %(value)r" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2593 #, python-format msgid "invalid choice: %(value)r (choose from %(choices)s)" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2671 #, python-format msgid "%(prog)s: error: %(message)s\n" msgstr "" linkchecker-10.5.0/po/nl_NL.po000066400000000000000000002054541466565367000160730ustar00rootroot00000000000000# Dutch translation for LinkChecker. # This file is distributed under the same license as the LinkChecker package. # Gideon van Melle, 2021. # msgid "" msgstr "" "Project-Id-Version: LinkChecker\n" "Report-Msgid-Bugs-To: https://github.com/linkchecker/linkchecker\n" "POT-Creation-Date: 2024-08-27 18:47+0000\n" "PO-Revision-Date: 2022-11-19 14:59+0100\n" "Last-Translator: Gideon van Melle \n" "Language-Team: \n" "Language: nl_NL\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.2\n" #: ../linkcheck/director/__init__.py:36 #, python-format msgid "Problem using login URL: %(msg)s." msgstr "Fout met login URL: %(msg)s." #: ../linkcheck/director/__init__.py:39 #, python-format msgid "Error using login URL: %(msg)s." msgstr "Fout met login URL: %(msg)s." #: ../linkcheck/director/__init__.py:44 #, python-format msgid "Error starting log output: %(msg)s." msgstr "Fout startlogboekuitvoer: %(msg)s." #: ../linkcheck/director/__init__.py:60 msgid "" "Could not start a new thread. Check that the current user is allowed to " "start new threads." msgstr "" "Kon niet beginnen met een nieuwe draad. Controleer of de huidige gebruiker " "nieuwe threads mag starten." #: ../linkcheck/director/__init__.py:93 msgid "interrupt; waiting for active threads to finish" msgstr "onderbreking; wachten op actieve threads te voltooien" #: ../linkcheck/director/__init__.py:94 msgid "another interrupt will exit immediately" msgstr "een andere interrupt zal onmiddellijk afsluiten" #: ../linkcheck/director/__init__.py:110 msgid "user abort; force shutdown" msgstr "gebruikersafboren; force shutdown" #: ../linkcheck/director/aggregator.py:54 #, fuzzy, python-format msgid "Could not parse cookie file: %s. %s" msgstr "Kan cookie-bestand %s niet lezen" #: ../linkcheck/director/aggregator.py:188 msgid "These URLs are still active:" msgstr "Deze URL's zijn nog steeds actief:" #: ../linkcheck/director/aggregator.py:200 #, python-format msgid "" "%(num)d URLs are still active. After a timeout of %(timeout)s the active " "URLs will stop." msgstr "" "%(num)d URL's zijn nog steeds actief. Na een time-out van %(timeout)s " "stoppen de actieve URL's." #: ../linkcheck/director/console.py:38 #, python-format msgid "%2d thread active" msgid_plural "%2d threads active" msgstr[0] "%2d rode draad actief" msgstr[1] "%2d threads actief" #: ../linkcheck/director/console.py:40 #, python-format msgid "%5d link queued" msgid_plural "%5d links queued" msgstr[0] "%5d koppeling in de wachtrij" msgstr[1] "%5d koppelingen in de wachtrij" #: ../linkcheck/director/console.py:42 #, python-format msgid "%4d link" msgid_plural "%4d links" msgstr[0] "%4d link" msgstr[1] "%4d links" #: ../linkcheck/director/console.py:44 #, python-format msgid "%3d URL" msgid_plural "%3d URLs" msgstr[0] "%3d URL" msgstr[1] "URL's %3d" #: ../linkcheck/director/console.py:46 #, python-format msgid "runtime %s" msgstr "runtime %s" #: ../linkcheck/director/console.py:66 #, python-format msgid "" "********** Oops, I did it again. *************\n" "\n" "You have found an internal error in LinkChecker. Please write a bug report\n" "at %s\n" "and include the following information:\n" "- the URL or file you are testing\n" "- the system information below\n" "\n" "When using the commandline client:\n" "- your commandline arguments and any custom configuration files.\n" "- the output of a debug run with option \"-Dall\"\n" "\n" "Not disclosing some of the information above due to privacy reasons is ok.\n" "I will try to help you nonetheless, but you have to give me something\n" "I can work with ;) .\n" msgstr "" "Oeps, ik deed het weer. *************\n" "\n" "U hebt een interne fout gevonden in LinkChecker. Schrijf een bugrapport\n" "bij %s\n" "en de volgende gegevens bevatten:\n" "- de URL of het bestand dat u test\n" "- de onderstaande systeeminformatie\n" "\n" "Wanneer u de commandlineclient gebruikt:\n" "- uw commandlineargumenten en eventuele aangepaste configuratiebestanden.\n" "- de output van een foutopsporingsrun met optie \"-Dall\"\n" "\n" "Niet openbaar maken van een aantal van de bovenstaande informatie als gevolg " "van privacy redenen is ok.\n" "Ik zal je toch proberen te helpen, maar je moet me iets geven.\n" "Ik kan met ;) werken.\n" #: ../linkcheck/director/console.py:94 msgid "******** LinkChecker internal error, over and out ********" msgstr "Interne fout van LinkChecker, over en uit ****" #: ../linkcheck/director/console.py:140 msgid "System info:" msgstr "Systeeminformatie:" #: ../linkcheck/director/console.py:142 msgid "Released on:" msgstr "Uitgebracht op:" #: ../linkcheck/director/console.py:144 ../linkcheck/command/linkchecker.py:130 #, python-format msgid "Python %(version)s on %(platform)s" msgstr "Python %(version)s op %(platform)s" #: ../linkcheck/director/console.py:152 msgid "Local time:" msgstr "Lokale tijd:" #: ../linkcheck/director/console.py:153 msgid "sys.argv:" msgstr "sys.argv:" #: ../linkcheck/director/console.py:158 msgid "released" msgstr "vrijgegeven" #: ../linkcheck/plugins/syntaxchecks.py:56 msgid "HTML syntax check plugin is broken. Fixes welcome." msgstr "HTML syntax check plugin is kapot. Fixes welkom." #: ../linkcheck/plugins/syntaxchecks.py:74 msgid "valid HTML syntax" msgstr "geldige HTML-syntaxis" #: ../linkcheck/plugins/syntaxchecks.py:81 #, python-format msgid "HTML syntax check plugin error: %(msg)s " msgstr "HTML-syntaxiscontrole-plugin fout: %(msg)s " #: ../linkcheck/plugins/syntaxchecks.py:114 msgid "valid CSS syntax" msgstr "geldige CSS-syntaxis" #: ../linkcheck/plugins/syntaxchecks.py:121 #, python-format msgid "CSS syntax check plugin error: %(msg)s " msgstr "CSS syntaxiscontrole-plugin fout: %(msg)s " #: ../linkcheck/plugins/syntaxchecks.py:132 #, python-format msgid "%(w3type)s validation error at line %(line)s col %(column)s: %(msg)s" msgstr "%(w3type)s validatiefout bij regel %(line)s col %(column)s: %(msg)s" #: ../linkcheck/plugins/syntaxchecks.py:136 #, python-format msgid "%(w3type)s validation error at line %(line)s: %(msg)s" msgstr "%(w3type)s validatiefout bij regel %(line)s: %(msg)s" #: ../linkcheck/plugins/markdowncheck.py:88 #: ../linkcheck/plugins/regexcheck.py:45 #, fuzzy, python-format msgid "Invalid regex pattern %r: %s" msgstr "ongeldige lege waarde voor %s: %s\n" #: ../linkcheck/plugins/regexcheck.py:61 #, python-format msgid "Found %(match)r at line %(line)d in link contents." msgstr "Gevonden %(match)r bij regel %(line)d in de inhoud van de koppeling." #: ../linkcheck/plugins/sslcertcheck.py:70 msgid "certificate did not include \"notAfter\" information" msgstr "certificaat bevat geen \"notAfter\" informatie" #: ../linkcheck/plugins/sslcertcheck.py:73 msgid "SSL verification is disabled; enable the sslverify option" msgstr "SSL-verificatie is uitgeschakeld; de optie sslverify inschakelen" #: ../linkcheck/plugins/sslcertcheck.py:85 #, python-format msgid "Invalid SSL certificate \"notAfter\" value %r" msgstr "Ongeldig SSL-certificaat \"notAfter\" waarde %r" #: ../linkcheck/plugins/sslcertcheck.py:94 #, python-format msgid "SSL certificate is expired on %(expire)s." msgstr "SSL-certificaat is verlopen op %(expire)s." #: ../linkcheck/plugins/sslcertcheck.py:100 #, python-format msgid "SSL certificate expires on %(expire)s and is only %(valid)s valid." msgstr "" "SSL-certificaat verloopt op %(expire)s en is alleen geldig voor %(valid)s." #: ../linkcheck/plugins/sslcertcheck.py:104 #, python-format msgid "SSL certificate expires on %(expire)s and is %(valid)s valid." msgstr "SSL-certificaat verloopt op %(expire)s en is %(valid)s geldig." #: ../linkcheck/plugins/sslcertcheck.py:118 #: ../linkcheck/configuration/confparse.py:98 #: ../linkcheck/configuration/confparse.py:116 #, python-format msgid "invalid value for %s: %d must not be less than %d" msgstr "ongeldige waarde voor %s: %d mag niet lager zijn dan %d" #: ../linkcheck/plugins/locationinfo.py:46 #, python-format msgid "URL is located in %(location)s." msgstr "URL bevindt zich in %(location)s." #: ../linkcheck/plugins/viruscheck.py:101 msgid "clamd is not ready for stream scanning" msgstr "clamd is niet klaar voor stream scanning" #: ../linkcheck/plugins/viruscheck.py:160 msgid "ScannerDaemonOutputFormat must be disabled" msgstr "ScannerDaemonOutputFormat moet zijn uitgeschakeld" #: ../linkcheck/plugins/viruscheck.py:163 msgid "only one of TCPSocket and LocalSocket must be enabled" msgstr "slechts één van TCPSocket en LocalSocket moet ingeschakeld zijn" #: ../linkcheck/plugins/viruscheck.py:193 msgid "one of TCPSocket or LocalSocket must be enabled" msgstr "één van TCPSocket of LocalSocket moet ingeschakeld zijn" #: ../linkcheck/plugins/viruscheck.py:229 msgid "Could not connect to ClamAV daemon." msgstr "Kon geen verbinding maken met ClamAV daemon." #: ../linkcheck/plugins/anchorcheck.py:70 #, python-format msgid "Anchor `%(name)s' (decoded: `%(decoded)s') not found." msgstr "Anker '%(name)s' (gedecodeerd: '%(decoded)s') niet gevonden." #: ../linkcheck/plugins/anchorcheck.py:71 #, python-format msgid "Available anchors: %(anchors)s." msgstr "Beschikbare ankers: %(anchors)s." #: ../linkcheck/cookies.py:46 #, fuzzy msgid "No entries found" msgstr "Er is geen NNTP-server gevonden." #: ../linkcheck/cmdline.py:61 #, python-format msgid "Error: %(msg)s" msgstr "Fout: %(msg)s" #: ../linkcheck/cmdline.py:63 #, python-format msgid "Execute '%(program)s -h' for help" msgstr "Voer '%(program)s -h' uit voor hulp" #: ../linkcheck/configuration/__init__.py:227 #, python-format msgid "Configuration file %r does not exist." msgstr "Configuratiebestand %r bestaat niet." #: ../linkcheck/configuration/__init__.py:229 #, python-format msgid "Configuration file %r is not readable." msgstr "Configuratiebestand %r is niet leesbaar." #: ../linkcheck/configuration/__init__.py:239 msgid "missing user or URL pattern in authentication data." msgstr "ontbrekende gebruiker of URL-patroon in verificatiegegevens." #: ../linkcheck/configuration/__init__.py:274 msgid "activating text logger output." msgstr "activatie van tekstlogger output." #: ../linkcheck/configuration/__init__.py:285 msgid "no user/password authentication data found for login URL." msgstr "" "geen gebruikers-/wachtwoordverificatiegegevens gevonden voor login-URL." #: ../linkcheck/configuration/__init__.py:289 msgid "login URL is not a HTTP URL." msgstr "login URL is geen HTTP URL." #: ../linkcheck/configuration/__init__.py:293 msgid "login URL is incomplete." msgstr "login URL is onvolledig." #: ../linkcheck/configuration/__init__.py:296 #, python-format msgid "disabling login URL %(url)s." msgstr "uitschakelen van login URL %(url)s." #: ../linkcheck/configuration/__init__.py:349 #, python-format msgid "could not create plugin directory %(dirname)r: %(errmsg)r" msgstr "kan geen plugin directory %(dirname)r aanmaken: %(errmsg)r" #: ../linkcheck/configuration/__init__.py:397 #, python-format msgid "" "could not copy initial configuration file %(src)r to %(dst)r: %(errmsg)r" msgstr "" "kon het oorspronkelijke configuratiebestand %(src)r niet kopiëren naar " "%(dst)r: %(errmsg)r" #: ../linkcheck/configuration/confparse.py:62 #, fuzzy, python-format msgid "configuration files %s contain no sections." msgstr "Configuratiebestand %r bestaat niet." #: ../linkcheck/configuration/confparse.py:75 #, python-format msgid "Error parsing configuration: %s" msgstr "Fout parsing configuratie: %s" #: ../linkcheck/configuration/confparse.py:83 #, python-format msgid "invalid empty value for %s: %s\n" msgstr "ongeldige lege waarde voor %s: %s\n" #: ../linkcheck/configuration/confparse.py:103 #: ../linkcheck/configuration/confparse.py:121 #, python-format msgid "invalid value for %s: %d must not be greater than %d" msgstr "ongeldige waarde voor %s: %d mag niet groter zijn dan %d" #: ../linkcheck/configuration/confparse.py:136 msgid "" "The blacklist section in linkcheckerrc is deprecated, please rename to " "failures" msgstr "" "De blacklist sectie in linkcheckeerrc is afgeschaft. Hernoem naar failures" #: ../linkcheck/configuration/confparse.py:237 #, python-format msgid "missing auth part in entry %(val)r" msgstr "ontbrekend auth-gedeelte in de vermelding %(val)r" #: ../linkcheck/configuration/confparse.py:247 #, python-format msgid "invalid login URL `%s'. Only HTTP and HTTPS URLs are supported." msgstr "" "ongeldige login URL `%s’. Alleen HTTP- en HTTPS-URL's worden ondersteund." #: ../linkcheck/configuration/confparse.py:276 #, python-format msgid "" "The configuration file %s contains password information (in section [%s] and " "options %s) and the file is readable by others. Please make the file only " "readable by you." msgstr "" "Het configuratiebestand bevat %s wachtwoordinformatie (in sectie [%s] en " "opties %s) en het bestand is leesbaar voor anderen. Maak het bestand alleen " "leesbaar voor u." #: ../linkcheck/configuration/confparse.py:285 #, python-format msgid "For example execute 'chmod go-rw %s'." msgstr "Voer bijvoorbeeld 'chmod go-rw %s' uit." #: ../linkcheck/configuration/confparse.py:290 #, python-format msgid "See %(url)s for more info on setting file permissions." msgstr "" "Zie %(url)s voor meer informatie over het instellen van bestandsmachtigingen." #: ../linkcheck/lc_cgi.py:215 #, fuzzy, python-format msgid "could not set locale %r: %s" msgstr "kon geen content krijgen: %(msg)s" #: ../linkcheck/lc_cgi.py:217 #, python-format msgid "unsupported language %r" msgstr "niet-ondersteunde taal %r" #: ../linkcheck/lc_cgi.py:222 msgid "empty url was given" msgstr "lege url werd gegeven" #: ../linkcheck/lc_cgi.py:224 #, python-format msgid "disallowed url %r was given" msgstr "niet-toegestane url %r werd gegeven" #: ../linkcheck/lc_cgi.py:226 msgid "no url was given" msgstr "geen url werd gegeven" #: ../linkcheck/lc_cgi.py:231 #, python-format msgid "invalid recursion level %r" msgstr "ongeldig recursieniveau %r" #: ../linkcheck/lc_cgi.py:237 #, python-format msgid "invalid %s option %r" msgstr "ongeldige %s optie %r" #: ../linkcheck/lc_cgi.py:264 #, python-format msgid "" "\n" "\n" "\n" "LinkChecker Online Error\n" "\n" "
\n" "Error: %s
\n" "The LinkChecker Online script has encountered an error. Please ensure\n" "that your provided URL link begins with http:// and\n" "contains only these characters: A-Za-z0-9./_~-

\n" "Errors are logged.\n" "
\n" "\n" "" msgstr "" "\n" "\n" "\n" "LinkChecker Online fout\n" "\n" "
\n" "Fout: %s
Er is een fout opgetreden in het script LinkChecker " "Online. Zorg ervoor \n" "dat uw meegeleverde URL-koppeling begint met http:// en\n" "alleen deze tekens bevat: A-Za-z0-9./_~-

\n" "Fouten worden geregistreerd.
\n" "\n" "" #: ../linkcheck/checker/fileurl.py:142 #, python-format msgid "Could not get current working directory: %(msg)s" msgstr "Kan de huidige werkmap niet krijgen: %(msg)s" #: ../linkcheck/checker/fileurl.py:175 ../linkcheck/checker/fileurl.py:339 msgid "Added trailing slash to directory." msgstr "Schuine streep toegevoegd aan de map." #: ../linkcheck/checker/fileurl.py:198 ../linkcheck/checker/fileurl.py:352 msgid "" "local files are only checked without parent URL or when the parent URL is " "also a file" msgstr "" "lokale bestanden worden alleen gecontroleerd zonder bovenliggende URL of " "wanneer de bovenliggende URL ook een bestand is" #: ../linkcheck/checker/fileurl.py:203 ../linkcheck/checker/fileurl.py:367 msgid "directory" msgstr "folder" #: ../linkcheck/checker/fileurl.py:222 #, python-format msgid "" "The URL path %(path)r is not the same as the system path %(realpath)r. You " "should always use the system path in URLs." msgstr "" "Het URL-pad %(path)r is niet hetzelfde als het systeempad %(realpath)r. U " "moet het systeempad altijd gebruiken in URL's." #: ../linkcheck/checker/fileurl.py:360 #, python-format msgid "" "URL `%s' is a directory with an anchor. When checking local files " "AnchorCheck does not support anchors for directories." msgstr "" "URL `%s' is een directory met een anker. Bij het controleren van lokale " "bestanden ondersteunt AnchorCheck geen ankers voor mappen." #: ../linkcheck/checker/itmsservicesurl.py:31 msgid "Missing required url parameter" msgstr "Ontbrekende vereiste url-parameter" #: ../linkcheck/checker/urlbase.py:79 #, python-format msgid "URL has unparsable domain name: %(name)s" msgstr "URL heeft unparsable domeinnaam: %(name)s" #: ../linkcheck/checker/urlbase.py:163 msgid "The URL is outside of the domain filter, checked only syntax." msgstr "" "De URL bevindt zich buiten het domeinfilter. Alleen de syntaxis " "gecontroleerd." #: ../linkcheck/checker/urlbase.py:166 msgid "filtered" msgstr "gefilterd" #: ../linkcheck/checker/urlbase.py:216 #, python-format msgid "Leading or trailing whitespace in URL `%(url)s'." msgstr "Whitespace leiden of achtervolgen in URL `%(url)s'." #: ../linkcheck/checker/urlbase.py:340 #, python-format msgid "The URL with content type %r is not parseable." msgstr "De URL met inhoudstype %r is niet te parseren." #: ../linkcheck/checker/urlbase.py:445 msgid "URL is empty" msgstr "URL is leeg" #: ../linkcheck/checker/urlbase.py:460 #, python-format msgid "Effective URL %(url)r." msgstr "Effectieve URL %(url)r." #: ../linkcheck/checker/urlbase.py:467 #, python-format msgid "URL length %(len)d is longer than %(max)d." msgstr "URL-lengte %(len)d is langer dan %(max)d." #: ../linkcheck/checker/urlbase.py:517 ../linkcheck/checker/urlbase.py:523 #, python-format msgid "URL host %(host)r has invalid port" msgstr "URL-host %(host)r heeft ongeldige poort" #: ../linkcheck/checker/urlbase.py:530 msgid "URL has empty hostname" msgstr "URL heeft lege hostnaam" #: ../linkcheck/checker/urlbase.py:555 #, python-format msgid "URL %(url)s has obfuscated IP address %(ip)s" msgstr "URL %(url)s heeft verborgen IP-adres %(ip)s" #: ../linkcheck/checker/urlbase.py:591 msgid "Hostname not found" msgstr "Hostname niet gevonden" #: ../linkcheck/checker/urlbase.py:594 #, python-format msgid "Bad hostname %(host)r: %(msg)s" msgstr "Bad hostnaam %(host)r: %(msg)s" #: ../linkcheck/checker/urlbase.py:614 #, python-format msgid "could not get content: %(msg)s" msgstr "kon geen content krijgen: %(msg)s" #: ../linkcheck/checker/urlbase.py:669 #, python-format msgid "Content size %(size)s is larger than %(maxbytes)s." msgstr "De content grootte %(size)s is groter dan %(maxbytes)s." #: ../linkcheck/checker/urlbase.py:763 msgid "Content size is zero." msgstr "De content grootte is nul." #: ../linkcheck/checker/urlbase.py:800 ../linkcheck/checker/httpurl.py:348 msgid "File size too large" msgstr "Bestand te groot" #: ../linkcheck/checker/urlbase.py:881 #, python-format msgid "URL has unparsable domain name: %(domain)s" msgstr "URL heeft unparsable domeinnaam: %(domain)s" #: ../linkcheck/checker/unknownurl.py:32 #, python-format msgid "%(scheme)s URL ignored." msgstr "URL van %(scheme)s genegeerd." #: ../linkcheck/checker/unknownurl.py:34 msgid "ignored" msgstr "genegeerd" #: ../linkcheck/checker/unknownurl.py:36 msgid "URL is unrecognized or has invalid syntax" msgstr "URL is niet herkend of heeft ongeldige syntaxis" #: ../linkcheck/checker/mailtourl.py:88 #, python-format msgid "No mail addresses or email subject found in `%(url)s'." msgstr "Geen e-mailadressen of e-mailonderwerpen gevonden in '%(url)s'." #: ../linkcheck/checker/mailtourl.py:132 #, python-format msgid "Error parsing CGI values: %s" msgstr "Fout parsing CGI waarden: %s" #: ../linkcheck/checker/mailtourl.py:158 #, python-format msgid "" "Mail address `%(addr)s' too long. Allowed 256 chars, was %(length)d chars." msgstr "" "E-mailadres '%(addr)s' te lang. Toegestaan zijn 256 tekens, was %(length)d " "tekens." #: ../linkcheck/checker/mailtourl.py:168 #, python-format msgid "Missing `@' in mail address `%(addr)s'." msgstr "Ontbrekende '@' in e-mailadres '%(addr)s'." #: ../linkcheck/checker/mailtourl.py:177 #, python-format msgid "Missing local part of mail address `%(addr)s'." msgstr "Ontbrekend lokaal deel van e-mailadres '%(addr)s'." #: ../linkcheck/checker/mailtourl.py:184 #, python-format msgid "Missing domain part of mail address `%(addr)s'." msgstr "Ontbrekend domeingedeelte van e-mailadres '%(addr)s'." #: ../linkcheck/checker/mailtourl.py:192 #, python-format msgid "" "Local part of mail address `%(addr)s' too long. Allowed 64 chars, was " "%(length)d chars." msgstr "" "Lokaal deel van e-mailadres '%(addr)s' te lang. Toegestaan 64 tekens, was " "%(length)d tekens." #: ../linkcheck/checker/mailtourl.py:203 #, python-format msgid "" "Domain part of mail address `%(addr)s' too long. Allowed 255 chars, was " "%(length)d chars." msgstr "" "Domeinonderdeel van e-mailadres '%(addr)s' te lang. Toegestaan 255 tekens, " "was %(length)d tekens." #: ../linkcheck/checker/mailtourl.py:218 #, python-format msgid "Unquoted double quote or backslash in mail address `%(addr)s'." msgstr "" "Niet-geciteerde dubbele aanhalingstekens of schuine streep in e-mailadres " "'%(addr)s'." #: ../linkcheck/checker/mailtourl.py:227 #, python-format msgid "Local part of mail address `%(addr)s' may not start with a dot." msgstr "Lokaal deel van e-mailadres '%(addr)s' mag niet beginnen met een punt." #: ../linkcheck/checker/mailtourl.py:235 #, python-format msgid "Local part of mail address `%(addr)s' may not end with a dot." msgstr "Lokaal deel van e-mailadres '%(addr)s' mag niet eindigen met een punt." #: ../linkcheck/checker/mailtourl.py:243 #, python-format msgid "Local part of mail address `%(addr)s' may not contain two dots." msgstr "" "Het lokale deel van het e-mailadres '%(addr)s' mag geen dubbele punten " "bevatten." #: ../linkcheck/checker/mailtourl.py:253 #, python-format msgid "" "Local part of mail address `%(addr)s' contains unquoted character `%(char)s." msgstr "" "Lokaal deel van e-mailadres `%(addr)s' bevat niet-geciteerd teken `%(char)s." #: ../linkcheck/checker/mailtourl.py:271 #, python-format msgid "Domain part of mail address `%(addr)s' has invalid IP." msgstr "Domeinonderdeel van e-mailadres `%(addr)s' heeft ongeldig IP." #: ../linkcheck/checker/mailtourl.py:281 #, python-format msgid "Invalid domain part of mail address `%(addr)s'." msgstr "Ongeldig domeinonderdeel van e-mailadres `%(addr)s'." #: ../linkcheck/checker/mailtourl.py:289 #, python-format msgid "Invalid top level domain part of mail address `%(addr)s'." msgstr "Ongeldig domeindeel op het hoogste niveau van e-mailadres `%(addr)s'." #: ../linkcheck/checker/mailtourl.py:327 #, python-format msgid "No MX mail host for %(domain)s found." msgstr "Er is geen MX-mailhost voor %(domain)s gevonden." #: ../linkcheck/checker/mailtourl.py:336 #, python-format msgid "No host for %(domain)s found." msgstr "Er is geen host voor %(domain)s gevonden." #: ../linkcheck/checker/mailtourl.py:353 #, python-format msgid "Got invalid DNS answer %(answer)s for %(domain)s." msgstr "Ongeldig DNS-antwoord %(answer)s voor %(domain)s." #: ../linkcheck/checker/mailtourl.py:366 msgid "Valid mail address syntax" msgstr "Geldige syntaxis van het e-mailadres" #: ../linkcheck/checker/const.py:99 msgid "The effective URL is different from the original." msgstr "De effectieve URL is anders dan het origineel." #: ../linkcheck/checker/const.py:100 msgid "Could not get the content of the URL." msgstr "Kan de content van de URL niet krijgen." #: ../linkcheck/checker/const.py:101 msgid "The URL content size is too large." msgstr "De grootte van de URL-inhoud is te groot." #: ../linkcheck/checker/const.py:102 msgid "The URL content size is zero." msgstr "De grootte van de URL-inhoud is nul." #: ../linkcheck/checker/const.py:103 msgid "The URL content type is not parseable." msgstr "Het URL-inhoudstype kan niet worden geparseerd." #: ../linkcheck/checker/const.py:104 msgid "The URL is longer than the recommended size." msgstr "De URL is langer dan de aanbevolen grootte." #: ../linkcheck/checker/const.py:105 msgid "The URL contains leading or trailing whitespace." msgstr "De URL bevat toonaangevende of nakomende spaties." #: ../linkcheck/checker/const.py:106 msgid "The file: URL is missing a trailing slash." msgstr "Het bestand: URL mist een schuine eindstreep." #: ../linkcheck/checker/const.py:108 msgid "The file: path is not the same as the system specific path." msgstr "Het bestand: pad is niet hetzelfde als het systeemspecifieke pad." #: ../linkcheck/checker/const.py:111 msgid "A local directory with an anchor, not supported by AnchorCheck." msgstr "Een lokale directory met een anker, niet ondersteund door AnchorCheck." #: ../linkcheck/checker/const.py:112 msgid "The ftp: URL is missing a trailing slash." msgstr "De ftp: URL mist een afsluitende schuine streep." #: ../linkcheck/checker/const.py:113 msgid "The URL had no content." msgstr "De URL had geen inhoud." #: ../linkcheck/checker/const.py:114 msgid "An error occurred while storing a cookie." msgstr "Er is een fout opgetreden tijdens het opslaan van een cookie." #: ../linkcheck/checker/const.py:115 msgid "The URL request was rate limited." msgstr "Het URL-verzoek was beperkt." #: ../linkcheck/checker/const.py:116 msgid "Redirected to a different URL." msgstr "" #: ../linkcheck/checker/const.py:117 msgid "The mail MX host could not be found." msgstr "De E-mail MX-host kon niet worden gevonden." #: ../linkcheck/checker/const.py:118 msgid "The IP is obfuscated." msgstr "De IP is verborgen." #: ../linkcheck/checker/const.py:119 msgid "XML could not be parsed." msgstr "XML kon niet worden ontleed." #: ../linkcheck/checker/ftpurl.py:75 msgid "Got no answer from FTP server" msgstr "Heb je geen antwoord van FTP-server" #: ../linkcheck/checker/ftpurl.py:78 #, python-format msgid "Remote host has closed connection: %(msg)s" msgstr "Externe host heeft verbinding met %(msg)s verbroken" #: ../linkcheck/checker/ftpurl.py:124 msgid "Missing trailing directory slash in ftp url." msgstr "Ontbrekende eind schuine streep voor folder in ftp url." #: ../linkcheck/checker/ftpurl.py:188 msgid "FTP file size too large" msgstr "FTP-bestandsgrootte te groot" #: ../linkcheck/checker/httpurl.py:138 msgid "Access denied by robots.txt, checked only syntax." msgstr "Toegang geweigerd door robots.txt, alleen syntaxis gecontroleerd." #: ../linkcheck/checker/httpurl.py:139 msgid "syntax OK" msgstr "syntaxis OK" #: ../linkcheck/checker/httpurl.py:283 #, fuzzy, python-format msgid "Redirected to `%(url)s' status: %(code)d %(reason)s." msgstr "Doorgestuurd naar `%(url)s'." #: ../linkcheck/checker/httpurl.py:336 msgid "OK" msgstr "OK" #: ../linkcheck/checker/dnsurl.py:46 #, python-format msgid "%(host)s resolved to IPs %(ips)s" msgstr "%(host)s opgelost voor IPS %(ips)s" #: ../linkcheck/checker/dnsurl.py:48 #, python-format msgid "%(host)r could not be resolved" msgstr "%(host)r kan niet worden opgelost" #: ../linkcheck/command/setup_config.py:49 msgid "Running with python -O disables debugging." msgstr "Uitvoeren met python -O schakelt foutopsporing uit." #: ../linkcheck/command/setup_config.py:81 #, python-format msgid "blacklist is deprecated for option %(option)s, using failures instead" msgstr "" "blacklist is afgeschaft voor optie %(option)s, inplaats hiervan worden " "failures gebruikt" #: ../linkcheck/command/setup_config.py:87 #: ../linkcheck/command/setup_config.py:133 #, python-format msgid "Unknown logger type %(type)r in %(output)r for option %(option)s" msgstr "Onbekend loggertype %(type)r in %(output)r voor optie %(option)s" #: ../linkcheck/command/setup_config.py:94 #: ../linkcheck/command/setup_config.py:144 #, python-format msgid "Unknown encoding %(encoding)r in %(output)r for option %(option)s" msgstr "Onbekende codering %(encoding)r in %(output)r voor optie %(option)s" #: ../linkcheck/command/setup_config.py:127 #, python-format msgid "" "blacklist logger is deprecated for option %(option)s, using failures instead" msgstr "" "blacklist logger is afgeschaft voor optie %(option)s, inplaats hiervan " "worden failures gebruikt" #: ../linkcheck/command/setup_config.py:159 #, python-format msgid "Enter LinkChecker HTTP/FTP password for user %(user)s:" msgstr "" "Voer het HTTP/FTP-wachtwoord van LinkChecker in voor gebruikers %(user)s:" #: ../linkcheck/command/setup_config.py:163 msgid "Enter LinkChecker HTTP/FTP password:" msgstr "Voer het HTTP/FTP-wachtwoord van LinkChecker in:" #: ../linkcheck/command/setup_config.py:181 #, python-format msgid "Illegal argument %(arg)r for option %(option)s" msgstr "Illegaal argument %(arg)r voor optie %(option)s" #: ../linkcheck/command/setup_config.py:198 #, python-format msgid "Enter LinkChecker password for user %(user)s at %(strpattern)s:" msgstr "" "Voer het wachtwoord van LinkChecker in voor gebruikers %(user)s bij " "%(strpattern)s:" #: ../linkcheck/command/setup_config.py:207 #, fuzzy, python-format msgid "Cookie file %s does not exist." msgstr "Configuratiebestand %r bestaat niet." #: ../linkcheck/command/setup_config.py:210 #, python-format msgid "Could not read cookie file %s" msgstr "Kan cookie-bestand %s niet lezen" #: ../linkcheck/command/linkchecker.py:50 msgid "Running as root user; dropping privileges by changing user to nobody." msgstr "" "Wordt uitgevoerd als hoofdgebruiker; privileges worden verwijderd door de " "gebruiker in niemand te veranderen." #: ../linkcheck/command/linkchecker.py:124 #, python-format msgid "Invalid debug level %(level)r" msgstr "Ongeldig debugniveau %(level)r" #: ../linkcheck/command/linkchecker.py:140 #, fuzzy, python-format msgid "Config file %s does not exist." msgstr "Configuratiebestand %r bestaat niet." #: ../linkcheck/command/linkchecker.py:143 #, fuzzy, python-format msgid "Could not read config file %s." msgstr "Kan cookie-bestand %s niet lezen" #: ../linkcheck/command/linkchecker.py:176 msgid "no files or URLs given" msgstr "geen bestanden of URL's gegeven" #: ../linkcheck/command/linkchecker.py:184 #, python-format msgid "" "Overwrite profiling file %(file)r?\n" "Press Ctrl-C to cancel, RETURN to continue." msgstr "" "Overschrijven profilering bestand %(file)r?\n" "Druk op Ctrl-C om te annuleren, RETURN om door te gaan." #: ../linkcheck/command/linkchecker.py:192 msgid "Canceled." msgstr "Geannuleerd." #: ../linkcheck/command/linkchecker.py:199 msgid "" "The `yappi' Python module is not installed, therefore the --profile option " "is disabled." msgstr "" "De 'yappi' Python module is niet geïnstalleerd, daarom is de --profiel optie " "uitgeschakeld." #: ../linkcheck/command/linkchecker.py:218 msgid "Dumping memory statistics..." msgstr "Dumping geheugen statistieken ..." #: ../linkcheck/command/linkchecker.py:220 #, python-format msgid "The memory dump has been written to `%(filename)s'." msgstr "De geheugendump is geschreven naar '%(filename)s'." #: ../linkcheck/command/arg_parser.py:28 #, fuzzy msgid "" "NOTES\n" " o URLs on the command line starting with \"ftp.\" are treated like\n" " \"ftp://ftp.\", URLs starting with \"www.\" are treated like \"http://www." "\".\n" " You can also give local files as arguments.\n" " o If you have your system configured to automatically establish a\n" " connection to the internet (e.g. with diald), it will connect when\n" " checking links not pointing to your local system.\n" " See the --ignore-url option on how to prevent this.\n" " o Javascript links are currently ignored.\n" " o If your platform does not support threading, LinkChecker disables it\n" " automatically.\n" " o You can supply multiple user/password pairs in a configuration file.\n" msgstr "" "Notities\n" " o URL's op de opdrachtregel die beginnen met \"ftp\" worden behandeld als\n" " \"ftp://ftp\", URL's die beginnen met \"www.\" worden behandeld als " "\"http://www\".\n" " U lokale bestanden ook als argumenten opgeven.\n" " o Als u uw systeem hebt geconfigureerd om automatisch te\n" " verbinden met internet (bijvoorbeeld met diald), zal er verbinding\n" " worden gemaakt wanneer externe links worden gecontroleerd.\n" " Zie de optie --ignore-url over hoe dit te voorkomen.\n" " o Javascript-koppelingen worden momenteel genegeerd.\n" " o Als uw platform geen ondersteuning biedt voor threading, \n" " schakelt LinkChecker het automatisch uit.\n" " o U kunt meerdere gebruikers-/wachtwoordparen in een configuratiebestand " "aanleveren.\n" " o Bij het controleren van 'news:' links hoeft de opgegeven NNTP-host niet\n" " hetzelfde te zijn als de host van de gebruiker die door uw pagina's " "bladert.\n" #: ../linkcheck/command/arg_parser.py:44 msgid "" "PROXY SUPPORT\n" "To use a proxy on Unix or Windows set $http_proxy or $https_proxy\n" "to the proxy URL. The URL should be of the form\n" "\"http://[:@][:]\".\n" "LinkChecker also detects manual proxy settings of Internet Explorer under\n" "Windows systems. On a Mac use the Internet Config to select a proxy.\n" "\n" "LinkChecker honors the $no_proxy environment variable. It can be a list\n" "of domain names for which no proxy will be used.\n" "\n" "Setting a HTTP proxy on Unix for example looks like this:\n" "\n" " export http_proxy=\"http://proxy.example.com:8080\"\n" "\n" "Proxy authentication is also supported:\n" "\n" " export http_proxy=\"http://user1:mypass@proxy.example.org:8081\"\n" "\n" "Setting a proxy on the Windows command prompt:\n" "\n" " set http_proxy=http://proxy.example.com:8080\n" "\n" msgstr "" "PROXY-ONDERSTEUNING\n" "Een proxy gebruiken op Unix- of Windows-set $http_proxy, $https_proxy of " "$ftp_proxy\n" "naar de proxy-URL. De URL moet van het formulier zijn\n" "\"http://[ :@][:]\".\n" "LinkChecker detecteert ook handmatige proxy-instellingen van Internet " "Explorer onder\n" "Windows-systemen, en gconf of KDE op Linux-systemen.\n" "Gebruik op een Mac de Internet Config om een proxy te selecteren.\n" "\n" "LinkChecker honoreert de variabele $no_proxy-omgeving. Het kan een lijst " "zijn\n" "van domeinnamen waarvoor geen proxy zal worden gebruikt.\n" "\n" "Het instellen van een HTTP-proxy op Unix ziet er bijvoorbeeld als volgt " "uit:\n" "\n" "export http_proxy=\"http://proxy.example.com:8080\"\n" "\n" "Proxyverificatie wordt ook ondersteund:\n" "\n" "export http_proxy=\"http://user1:mypass@proxy.example.org:8081\"\n" "\n" "Een proxy instellen op de opdrachtprompt van Windows:\n" "\n" "stel http_proxy=http://proxy.example.com:8080 in\n" "\n" #: ../linkcheck/command/arg_parser.py:70 msgid "" "REGULAR EXPRESSIONS\n" "Only Python regular expressions are accepted by LinkChecker.\n" "See https://docs.python.org/howto/regex.html for an introduction in\n" "regular expressions.\n" "\n" "The only addition is that a leading exclamation mark negates\n" "the regular expression.\n" msgstr "" "REGULIERE EXPRESSIES\n" "Alleen gewone Python-expressies worden geaccepteerd door LinkChecker.\n" "Zie https://docs.python.org/howto/regex.html voor een introductie in\n" "reguliere expressies.\n" "\n" "De enige toevoeging is dat een uitroepteken vooraan\n" "de reguliere expressie ontkent.\n" #: ../linkcheck/command/arg_parser.py:81 msgid "" "COOKIE FILES\n" "A cookie file contains standard RFC 805 header data with the following\n" "possible names:\n" "Scheme (optional)\n" " Sets the scheme the cookies are valid for; default scheme is 'http'.\n" "Host (required)\n" " Sets the domain the cookies are valid for.\n" "Path (optional)\n" " Gives the path the cookies are value for; default path is '/'.\n" "Set-cookie (optional)\n" " Set cookie name/value. Can be given more than once.\n" "\n" "Multiple entries are separated by a blank line.\n" "\n" "The example below will send two cookies to all URLs starting with\n" "'http://example.org/hello/' and one to all URLs starting\n" "with 'https://example.com/':\n" "\n" "Host: example.org\n" "Path: /hello\n" "Set-cookie: ID=\"smee\"\n" "Set-cookie: spam=\"egg\"\n" "\n" "Scheme: https\n" "Host: example.com\n" "Set-cookie: baggage=\"elitist\"; comment=\"hologram\"\n" msgstr "" "COOKIEBESTANDEN\n" "Een cookiebestand bevat standaard RFC 805-headergegevens met de volgende\n" "mogelijke namen:\n" "Regeling (optioneel)\n" " Hiermee stelt u het schema in waarvoor de cookies geldig zijn; " "standaardregeling is 'http'.\n" "Host (vereist)\n" " Hiermee stelt u het domein in waarvoor de cookies geldig zijn.\n" "Pad (optioneel)\n" " Geeft het pad de cookies zijn waarde voor; standaardpad is '/'.\n" "Set-cookie (optioneel)\n" " Stel cookienaam/waarde in. Kan meer dan eens gegeven worden.\n" "\n" "Meerdere vermeldingen worden gescheiden door een lege regel.\n" "\n" "In het onderstaande voorbeeld worden twee cookies naar alle URL's verzonden " "die beginnen met\n" "'http://example.org/hello/' en één voor alle URL's die beginnen\n" "met \"https://example.com/\":\n" "\n" "Gastheer: example.org\n" "Pad: /hallo\n" "Set-cookie: ID=\"smee\"\n" "Set-cookie: spam=\"egg\"\n" "\n" "Schema: https\n" "Gastheer: example.com\n" "Set-cookie: baggage=\"elitair\"; comment=\"hologram\"\n" #: ../linkcheck/command/arg_parser.py:111 msgid "" "RETURN VALUE\n" "The return value is non-zero when\n" " o invalid links were found or\n" " o warnings were found warnings are enabled\n" " o a program error occurred\n" msgstr "" "RETOURWAARDE\n" "De retourwaarde is niet-nul wanneer\n" " o ongeldige links zijn gevonden of\n" " o waarschuwingen zijn gevonden waarschuwingen zijn ingeschakeld\n" " o er is een programmafout opgetreden\n" #: ../linkcheck/command/arg_parser.py:120 msgid "" "EXAMPLES\n" "The most common use checks the given domain recursively, plus any\n" "single URL pointing outside of the domain:\n" " linkchecker http://www.example.org/\n" "Beware that this checks the whole site which can have several hundred\n" "thousands URLs. Use the -r option to restrict the recursion depth.\n" "\n" "Don't connect to mailto: hosts, only check their URL syntax. All other\n" "links are checked as usual:\n" " linkchecker --ignore-url=^mailto: www.example.org\n" "\n" "Checking local HTML files on Unix:\n" " linkchecker ../bla.html subdir/blubber.html\n" "\n" "Checking a local HTML file on Windows:\n" " linkchecker c:\\temp\\test.html\n" "\n" "You can skip the \"http://\" url part if the domain starts with \"www.\":\n" " linkchecker www.example.de\n" "\n" "You can skip the \"ftp://\" url part if the domain starts with \"ftp.\":\n" " linkchecker -r0 ftp.example.org\n" msgstr "" "VOORBEELDEN\n" "Het meest voorkomende gebruik controleert het gegeven domein recursief, " "plus\n" "enkele URL die buiten het domein wijzen:\n" " linkchecker http://www.example.org/\n" "Pas op dat dit de hele sitecontroleert die enkele honderden kan hebben\n" "duizenden URL's. Gebruik de optie -r om de recursiediepte te beperken.\n" "\n" "Maak geen verbinding met mailto: hosts, controleer alleen hun URL-syntaxis. " "Alle andere\n" "links worden gecontroleerd zoals gewoonlijk:\n" " linkchecker --ignore-url=^mailto: www.example.org\n" "\n" "Lokale HTML-bestanden op Unix controleren:\n" " Linkchecker.. /bla.html subdir/blubber.html\n" "\n" "Een lokaal HTML-bestand controleren in Windows:\n" " linkchecker c:\\temp\\test.html\n" "\n" "U het url-gedeelte 'http://' overslaan als het domein begint met 'www':\n" " linkchecker www.example.de\n" "\n" "U het url-gedeelte 'ftp://' overslaan als het domein begint met ftp:\n" " linkchecker -r0 ftp.example.org\n" #: ../linkcheck/command/arg_parser.py:146 msgid "" "OUTPUT TYPES\n" "Note that by default only errors and warnings are logged.\n" "You should use the --verbose option to see valid URLs,\n" "and when outputting a sitemap graph format.\n" "\n" "text Standard text output, logging URLs in keyword: argument fashion.\n" "html Log URLs in keyword: argument fashion, formatted as HTML.\n" " Additionally has links to the referenced pages. Invalid URLs have\n" " HTML and CSS syntax check links appended.\n" "csv Log check result in CSV format with one URL per line.\n" "gml Log parent-child relations between linked URLs as a GML sitemap\n" " graph.\n" "dot Log parent-child relations between linked URLs as a DOT sitemap\n" " graph.\n" "gxml Log check result as a GraphXML sitemap graph.\n" "xml Log check result as machine-readable XML.\n" "sql Log check result as SQL script with INSERT commands. An example\n" " script to create the initial SQL table is included as create.sql.\n" "failures\n" " Suitable for cron jobs. Logs the check result into a file\n" " $XDG_DATA_HOME/linkchecker/failures which only contains entries " "with\n" " invalid URLs and the number of times they have failed.\n" "none Logs nothing. Suitable for debugging or checking the exit code.\n" msgstr "" "UITVOERTYPEN\n" "Houd er rekening mee dat standaard alleen fouten en waarschuwingen worden " "geregistreerd.\n" "U moet de optie --verbose gebruiken om geldige URL's te zien,\n" "en bij het uitvoeren van een sitemapgrafiek.\n" "\n" "text Standaard tekstuitvoer, Logt URL's in trefwoord: argumentmode.\n" "html logt URL's in trefwoord: argumentmode, opgemaakt als HTML.\n" " Geeft ook links naar gerefereerde pagina’s. Ongeldige URL's hebben\n" " HTML- en CSS-syntax controle links toegevoegd.\n" "csv Log check resultaat in CSV formaat met één URL per regel.\n" "gml Log parent-child relaties tussen gekoppelde URL's als een GML-" "sitemap\n" " grafiek.\n" "dot Log parent-child relaties tussen gekoppelde URL's als DOT-sitemap\n" " grafiek.\n" "gxml Log check met als resultaat een GraphXML sitemap grafiek.\n" "xml Log check met als resultaat een machine-readable XML.\n" "sql Log check met als resultaat een SQL script met INSERT commando's. " "Een voorbeeld\n" " script om de eerste SQL-tabel te maken, is opgenomen als create." "sql.\n" "failures\n" " Geschikt voor cron jobs. Geeft het controleresultaat in een " "logbestand\n" " $XDG_DATA_HOME/linkchecker/failures die alleen vermeldingen bevat " "met ongeldig\n" " URL's en het aantal keren dat ze zijn mislukt.\n" "none Logt niets. Geschikt voor het debuggen of controleren van de exit " "code.\n" #: ../linkcheck/command/arg_parser.py:174 msgid "" "IGNORE WARNINGS\n" "The following warnings are recognized in the 'ignorewarnings' config\n" "file entry:\n" msgstr "" "WAARSCHUWINGEN NEGEREN\n" "De volgende waarschuwingen worden herkend in de 'ignorewarnings' config\n" "bestandsinvoer:\n" #: ../linkcheck/command/arg_parser.py:212 msgid "General options" msgstr "Algemene opties" #: ../linkcheck/command/arg_parser.py:219 #, python-format msgid "" "Use FILENAME as configuration file. Per default LinkChecker uses\n" "$XDG_CONFIG_HOME/linkchecker/linkcheckerrc (under Windows\n" "%%HOMEPATH%%\\.config\\linkchecker\\linkcheckerrc)." msgstr "" "Gebruik FILENAME als configuratiebestand. Per standaard gebruikt " "LinkChecker\n" "$XDG_CONFIG_HOME/linkchecker/linkcheckerrc (onder Windows\n" "%%HOMEPATH%%\\.config\\linkchecker\\linkcheckerrc)." #: ../linkcheck/command/arg_parser.py:230 msgid "" "Generate no more than the given number of threads. Default number\n" "of threads is 10. To disable threading specify a non-positive number." msgstr "" "Genereer niet meer dan het opgegeven aantal threads. Standaardnummer\n" "van draden is 10. Als u threading wilt uitschakelen, geeft u een niet-" "positief getal op." #: ../linkcheck/command/arg_parser.py:235 msgid "Print version and exit." msgstr "Versie afdrukken en afsluiten." #: ../linkcheck/command/arg_parser.py:241 msgid "Print available check plugins and exit." msgstr "Print beschikbare controle plugins en afsluiten." #: ../linkcheck/command/arg_parser.py:246 msgid "Read list of white-space separated URLs to check from stdin." msgstr "" "Lees de lijst met gescheiden URL's met witte ruimte om te controleren vanaf " "stdin." #: ../linkcheck/command/arg_parser.py:250 msgid "Output options" msgstr "Uitvoeropties" #: ../linkcheck/command/arg_parser.py:257 #, python-format msgid "" "Print debugging output for the given logger.\n" "Available loggers are %(lognamelist)s.\n" "Specifying 'all' is an alias for specifying all available loggers.\n" "The option can be given multiple times to debug with more\n" "than one logger.\n" "\n" "For accurate results, threading will be disabled during debug runs." msgstr "" "Druk debugging output voor de gegeven logger.\n" "Beschikbare loggers zijn %(lognamelist)s.\n" "Het opgeven van 'alles' is een alias voor het opgeven van alle beschikbare " "loggers.\n" "De optie kan meerdere keren worden gegeven om te debuggen met meer\n" "dan één logger.\n" "\n" "Voor nauwkeurige resultaten wordt threading uitgeschakeld tijdens " "foutopsporingsruns." #: ../linkcheck/command/arg_parser.py:274 #, python-format msgid "" "Output to a file linkchecker-out.TYPE, $XDG_DATA_HOME/linkchecker/failures " "for\n" "'failures' output, or FILENAME if specified.\n" "The ENCODING specifies the output encoding, the default is that of your\n" "locale.\n" "Valid encodings are listed at https://docs.python.org/library/codecs." "html#standard-encodings.\n" "The FILENAME and ENCODING parts of the 'none' output type will be ignored,\n" "else if the file already exists, it will be overwritten.\n" "You can specify this option more than once. Valid file output types\n" "are %(loggertypes)s. You can specify this option multiple times to output\n" "to more than one file. Default is no file output. Note that you can\n" "suppress all console output with the option '-o none'." msgstr "" "Uitvoer naar een bestand linkchecker-out.TYPE, $XDG_DATA_HOME/linkchecker/" "failures voor\n" "‘Failuren’ uitvoer of FILENAME indien opgegeven.\n" "De ENCODING specificeert de uitvoercodering, de standaard is die van uw\n" "locale.\n" "Geldige coderingen worden vermeld op https://docs.python.org/library/codecs." "html#standard-encodings.\n" "De FILENAME- en ENCODING onderdelen van het uitvoertype ‘none’ worden " "genegeerd,\n" "zoniet, als het bestand al bestaat, wordt het overschreven.\n" "U kunt deze optie meer dan eens opgeven. Geldige bestandstypen voor " "bestandsuitvoer\n" "zijn %(loggertypes)s. U kunt deze optie meerdere keren opgeven om uit te " "voeren\n" "naar meer dan één bestand. Standaard is: geen bestandsuitvoer. Houd er " "rekening mee dat u\n" "alle console-uitvoer kan onderdrukken met de optie '-o none'." #: ../linkcheck/command/arg_parser.py:294 msgid "Do not print check status messages." msgstr "Druk de statusberichten van de controle niet af." #: ../linkcheck/command/arg_parser.py:300 msgid "Don't log warnings. Default is to log warnings." msgstr "" "Log geen waarschuwingen in. Standaard is het registreren van waarschuwingen." #: ../linkcheck/command/arg_parser.py:308 #, python-format msgid "" "Specify output as %(loggertypes)s. Default output type is text.\n" "The ENCODING specifies the output encoding, the default is that of your\n" "locale.\n" "Valid encodings are listed at https://docs.python.org/library/codecs." "html#standard-encodings." msgstr "" "Geef uitvoer op als %(loggertypes)s. Standaarduitvoertype is tekst.\n" "De ENCODING geeft de uitvoercodering aan, de standaardinstelling is die van " "uw\n" "locale.\n" "Geldige coderingscodes worden vermeld op https://docs.python.org/library/" "codecs.html#standard-encodings." #: ../linkcheck/command/arg_parser.py:325 msgid "" "Quiet operation, an alias for '-o none'.\n" "This is only useful with -F." msgstr "" "Stille werking, een alias voor '-o none'.\n" "Dit is alleen nuttig met -F." #: ../linkcheck/command/arg_parser.py:336 msgid "Log all URLs. Default is to log only errors and warnings." msgstr "" "Log alle URL's in. Standaard is het registreren van alleen fouten en " "waarschuwingen." #: ../linkcheck/command/arg_parser.py:340 msgid "Checking options" msgstr "Opties controleren" #: ../linkcheck/command/arg_parser.py:346 msgid "" "Read a file with initial cookie data. The cookie data format is\n" "explained below." msgstr "" "Lees een bestand met de eerste cookiegegevens. Het cookiegegevensformaat is\n" "hieronder uitgelegd." #: ../linkcheck/command/arg_parser.py:356 msgid "Disable robots.txt checks" msgstr "Robots uitschakelen.txt controles" #: ../linkcheck/command/arg_parser.py:362 msgid "Check external URLs." msgstr "Externe URL's controleren." #: ../linkcheck/command/arg_parser.py:370 msgid "" "Only check syntax of URLs matching the given regular expression.\n" "This option can be given multiple times." msgstr "" "Controleer alleen de syntaxis van URL's die overeenkomen met de gegeven " "reguliere expressie.\n" "Deze optie kan meerdere keren worden gegeven." #: ../linkcheck/command/arg_parser.py:380 msgid "" "Check but do not recurse into URLs matching the given regular\n" "expression. This option can be given multiple times." msgstr "" "Controleren, maar niet opnieuw in URL's die overeenkomen met de gegeven " "reguliere\n" "Expressie. Deze optie kan meerdere keren worden gegeven." #: ../linkcheck/command/arg_parser.py:390 msgid "" "Read a password from console and use it for HTTP and FTP authorization.\n" "For FTP the default password is 'anonymous@'. For HTTP there is\n" "no default password. See also -u." msgstr "" "Lees een wachtwoord van de console en gebruik het voor HTTP- en FTP-" "autorisatie.\n" "Voor FTP is het standaardwachtwoord 'anonymous@'. Voor HTTP is er\n" "geen standaardwachtwoord. Zie ook -u." #: ../linkcheck/command/arg_parser.py:402 msgid "" "Check recursively all links up to given depth. A negative depth\n" "will enable infinite recursion. Default depth is infinite." msgstr "" "Controleer recursief alle verbindingen tot bepaalde diepte. Een negatieve " "diepte\n" "zal oneindige recursie mogelijk maken. Standaarddiepte is oneindig." #: ../linkcheck/command/arg_parser.py:412 msgid "Set the timeout for connection attempts in seconds." msgstr "Stel de time-out in voor verbindingspogingen in seconden." #: ../linkcheck/command/arg_parser.py:421 msgid "" "Try the given username for HTTP and FTP authorization.\n" "For FTP the default username is 'anonymous'. For HTTP there is\n" "no default username. See also -p." msgstr "" "Probeer de opgegeven gebruikersnaam voor HTTP- en FTP-autorisatie.\n" "Voor FTP is de standaard gebruikersnaam 'anoniem'. Voor HTTP is er\n" "geen standaard gebruikersnaam. Zie ook -p." #: ../linkcheck/command/arg_parser.py:431 msgid "" "Specify the User-Agent string to send to the HTTP server, for example\n" "\"Mozilla/4.0\". The default is \"LinkChecker/X.Y\" where X.Y is the " "current\n" "version of LinkChecker." msgstr "" "Geef bijvoorbeeld de User-Agent tekenreeks op die naar de HTTP-server moet " "worden verzonden\n" "\"Mozilla/4.0\". De standaardinstelling is \"LinkChecker/X.Y\" waarbij X.Y " "de huidige\n" "versie van LinkChecker." #: ../linkcheck/logger/html.py:127 ../linkcheck/logger/text.py:112 #, python-format msgid "Start checking at %s" msgstr "Begin met controleren op %s" #: ../linkcheck/logger/html.py:203 ../linkcheck/logger/text.py:165 #, python-format msgid ", line %d" msgstr ", regel %d" #: ../linkcheck/logger/html.py:205 ../linkcheck/logger/text.py:167 #, python-format msgid ", col %d" msgstr ", kolom %d" #: ../linkcheck/logger/html.py:207 ../linkcheck/logger/text.py:169 #, python-format msgid ", page %d" msgstr ", pagina %d" #: ../linkcheck/logger/html.py:246 ../linkcheck/logger/html.py:266 #: ../linkcheck/logger/text.py:185 ../linkcheck/logger/text.py:195 #, python-format msgid "%.3f seconds" msgstr "%.3f seconden" #: ../linkcheck/logger/html.py:311 ../linkcheck/logger/text.py:218 msgid "Valid" msgstr "Geldig" #: ../linkcheck/logger/html.py:316 ../linkcheck/logger/text.py:221 msgid "Error" msgstr "Fout" #: ../linkcheck/logger/html.py:323 msgid "Statistics" msgstr "Statistieken" #: ../linkcheck/logger/html.py:327 ../linkcheck/logger/text.py:300 #, python-format msgid "" "Content types: %(image)d image, %(text)d text, %(video)d video, %(audio)d " "audio, %(application)d application, %(mail)d mail and %(other)d other." msgstr "" "Inhoudstypen: %(image)d image, %(text)d text, %(video)d video, %(audio)d " "audio, %(application)d application, %(mail)d mail en %(other)d other." #: ../linkcheck/logger/html.py:335 ../linkcheck/logger/text.py:307 #, python-format msgid "URL lengths: min=%(min)d, max=%(max)d, avg=%(avg)d." msgstr "URL lengtes: min=%(min)d, max=%(max)d, avg=%(avg)d." #: ../linkcheck/logger/html.py:343 ../linkcheck/logger/text.py:315 msgid "No statistics available since no URLs were checked." msgstr "" "Er zijn geen statistieken beschikbaar omdat er geen URL's zijn gecontroleerd." #: ../linkcheck/logger/html.py:349 ../linkcheck/logger/text.py:231 msgid "That's it." msgstr "Dat was het." #: ../linkcheck/logger/html.py:352 #, python-format msgid "%d link checked." msgid_plural "%d links checked." msgstr[0] "%d link gecontroleerd." msgstr[1] "%d links gecontroleerd." #: ../linkcheck/logger/html.py:357 ../linkcheck/logger/text.py:240 #, python-format msgid "%d warning found" msgid_plural "%d warnings found" msgstr[0] "%d waarschuwing gevonden" msgstr[1] "%d waarschuwingen gevonden" #: ../linkcheck/logger/html.py:362 ../linkcheck/logger/text.py:250 #, python-format msgid " (%d ignored or duplicates not printed)" msgstr " (%d genegeerd of duplicaten niet afgedrukt)" #: ../linkcheck/logger/html.py:367 ../linkcheck/logger/text.py:255 #, python-format msgid "%d error found" msgid_plural "%d errors found" msgstr[0] "%d fout gevonden" msgstr[1] "%d fouten gevonden" #: ../linkcheck/logger/html.py:372 ../linkcheck/logger/text.py:265 #, python-format msgid " (%d duplicates not printed)" msgstr " (%d duplicaten niet afgedrukt)" #: ../linkcheck/logger/html.py:381 ../linkcheck/logger/text.py:273 #, python-format msgid "There was %(num)d internal error." msgid_plural "There were %(num)d internal errors." msgstr[0] "Er was een interne fout %(num)d." msgstr[1] "Er waren interne fouten %(num)d." #: ../linkcheck/logger/html.py:391 ../linkcheck/logger/__init__.py:397 #: ../linkcheck/logger/text.py:282 #, python-format msgid "Stopped checking at %(time)s (%(duration)s)" msgstr "Gestopt met controleren bij %(time)s (%(duration)s)" #: ../linkcheck/logger/html.py:401 #, python-format msgid "Read the documentation at %s" msgstr "Lees de documentatie op %s" #: ../linkcheck/logger/html.py:411 #, python-format msgid "Write comments and bugs to %s" msgstr "Schrijf opmerkingen en bugs naar %s" #: ../linkcheck/logger/failures.py:47 #, python-format msgid "%(blacklist)s file is deprecated please rename to failures" msgstr "%(blacklist)s bestand is afgeschaft, hernoem naar failures" #: ../linkcheck/logger/failures.py:99 #, python-format msgid "invalid line starting with '%(linestart)s' in %(failures)s" msgstr "ongeldige regel die begint met '%(linestart)s' in %(failures)s" #: ../linkcheck/logger/__init__.py:31 msgid "Real URL" msgstr "Echte URL" #: ../linkcheck/logger/__init__.py:32 msgid "Cache key" msgstr "Cachesleutel" #: ../linkcheck/logger/__init__.py:33 msgid "Result" msgstr "Resultaat" #: ../linkcheck/logger/__init__.py:34 msgid "Base" msgstr "Basis" #: ../linkcheck/logger/__init__.py:35 msgid "Name" msgstr "Naam" #: ../linkcheck/logger/__init__.py:36 msgid "Parent URL" msgstr "Bovenliggende URL" #: ../linkcheck/logger/__init__.py:37 msgid "Extern" msgstr "Extern" #: ../linkcheck/logger/__init__.py:38 msgid "Info" msgstr "Info" #: ../linkcheck/logger/__init__.py:39 msgid "Warning" msgstr "Waarschuwing" #: ../linkcheck/logger/__init__.py:40 msgid "D/L time" msgstr "D/L-tijd" #: ../linkcheck/logger/__init__.py:41 msgid "Size" msgstr "Grootte" #: ../linkcheck/logger/__init__.py:42 msgid "Check time" msgstr "De tijd controleren" #: ../linkcheck/logger/__init__.py:43 msgid "URL" msgstr "URL" #: ../linkcheck/logger/__init__.py:44 msgid "Level" msgstr "Niveau" #: ../linkcheck/logger/__init__.py:45 msgid "Modified" msgstr "Gewijzigd" #: ../linkcheck/logger/__init__.py:275 #, python-format msgid "Happy birthday for LinkChecker, I'm %d years old today!" msgstr "" "Gefeliciteerd met de verjaardag van LinkChecker, ik ben %d jaar oud vandaag!" #: ../linkcheck/logger/__init__.py:381 #, python-format msgid "created by %(app)s at %(time)s" msgstr "gemaakt door %(app)s op %(time)s" #: ../linkcheck/logger/__init__.py:385 ../linkcheck/logger/text.py:105 #, python-format msgid "Read the documentation at %(url)s" msgstr "Lees de documentatie op %(url)s" #: ../linkcheck/logger/__init__.py:388 ../linkcheck/logger/text.py:108 #, python-format msgid "Write comments and bugs to %(url)s" msgstr "Opmerkingen en bugs schrijven naar %(url)s" #: ../linkcheck/logger/text.py:65 msgid "Invalid value for wraplength. Using default." msgstr "" #: ../linkcheck/logger/text.py:230 msgid "The check has been interrupted; results are not complete." msgstr "De controle is onderbroken; resultaten zijn niet compleet." #: ../linkcheck/logger/text.py:232 #, python-format msgid "%d link" msgid_plural "%d links" msgstr[0] "%d link" msgstr[1] "%d links" #: ../linkcheck/logger/text.py:236 #, python-format msgid "in %d URL" msgid_plural "in %d URLs" msgstr[0] "in %d URL" msgstr[1] "in %d URL's" #: ../linkcheck/logger/text.py:238 msgid " checked." msgstr " aangevinkt." #: ../linkcheck/logger/text.py:292 msgid "Statistics:" msgstr "Statistieken:" #: ../linkcheck/logger/text.py:295 #, python-format msgid "Downloaded: %s." msgstr "Gedownload: %s." #: ../linkcheck/__init__.py:77 #, python-format msgid "Link pattern %r strict=%s" msgstr "" #: ../linkcheck/__init__.py:87 #, fuzzy, python-format msgid "invalid regular expression %r: %s" msgstr "ongeldig recursieniveau %r" #: ../linkcheck/__init__.py:111 msgid "CRITICAL" msgstr "KRITIEK" #: ../linkcheck/__init__.py:112 msgid "ERROR" msgstr "FOUT" #: ../linkcheck/__init__.py:113 msgid "WARN" msgstr "WAARSCHUWEN" #: ../linkcheck/__init__.py:114 msgid "WARNING" msgstr "WAARSCHUWING" #: ../linkcheck/__init__.py:115 msgid "INFO" msgstr "INFO" #: ../linkcheck/__init__.py:116 msgid "DEBUG" msgstr "FOUTOPSPORING" #: ../linkcheck/__init__.py:117 msgid "NOTSET" msgstr "NOT SET" #: ../linkcheck/strformat.py:165 #, python-format msgid "%(prefix)s%(duration).02f seconds" msgstr "%(prefix)s%(duration).02f seconden" #: ../linkcheck/strformat.py:170 #, python-format msgid "%d second" msgid_plural "%d seconds" msgstr[0] "%d seconde" msgstr[1] "%d seconden" #: ../linkcheck/strformat.py:171 #, python-format msgid "%d minute" msgid_plural "%d minutes" msgstr[0] "%d minuut" msgstr[1] "%d minuten" #: ../linkcheck/strformat.py:172 #, python-format msgid "%d hour" msgid_plural "%d hours" msgstr[0] "%d uur" msgstr[1] "%d uren" #: ../linkcheck/strformat.py:173 #, python-format msgid "%d day" msgid_plural "%d days" msgstr[0] "%d dag" msgstr[1] "%d dagen" #: ../linkcheck/strformat.py:174 #, python-format msgid "%d year" msgid_plural "%d years" msgstr[0] "%d jaar" msgstr[1] "%d jaren" #: ../linkcheck/strformat.py:245 #, python-format msgid "" "Could not import %(module)s for %(feature)s. Install %(module)s from %(url)s " "to use this feature." msgstr "" "Kan geen %(module)s importeren voor %(feature)s. Installeer %(module)s van " "%(url)s om deze functie te gebruiken." #: ../linkcheck/cache/robots_txt.py:77 #, python-format msgid "Relative Sitemap %s in %s discarded" msgstr "Relatieve sitemap %s in %s verwijderd" #: ../linkcheck/loader.py:40 #, python-format msgid "WARN: could not load module %s: %s" msgstr "" #: ../linkcheck/loader.py:57 #, fuzzy, python-format msgid "WARN: could not load file %s: %s" msgstr "Kan cookie-bestand %s niet lezen" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:228 #, python-format msgid "%(heading)s:" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:300 msgid "usage: " msgstr "gebruik: " #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:726 #, python-format msgid " (default: %(default)s)" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:780 #, python-format msgid "argument %(argument_name)s: %(message)s" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:886 msgid ".__call__() not defined" msgstr ".__call__() niet gedefinieerd" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1157 msgid "show program's version number and exit" msgstr "" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1219 #, fuzzy, python-format msgid "conflicting subparser: %s" msgstr "conflicterende optietekenreeks: %s" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1223 #, fuzzy, python-format msgid "conflicting subparser alias: %s" msgstr "conflicterende optietekenreeks: %s" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1258 #, python-format msgid "unknown parser %(parser_name)r (choices: %(choices)s)" msgstr "onbekende parser %(parser_name)r (keuzes: %(choices)s)" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1318 #, python-format msgid "argument \"-\" with mode %r" msgstr "argument \"-\" met modus %r" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1327 #, python-format msgid "can't open '%(filename)s': %(error)s" msgstr "kan ‘%(filename)s niet openen': %(error)s" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1536 #, python-format msgid "cannot merge actions - two groups are named %r" msgstr "kan geen acties samenvoegen - twee groepen worden %r genoemd" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1574 msgid "'required' is an invalid argument for positionals" msgstr "'vereist' is een ongeldig argument voor positionals" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1596 #, python-format msgid "" "invalid option string %(option)r: must start with a character " "%(prefix_chars)r" msgstr "" "ongeldige optietekenreeks %(option)r: moet beginnen met een teken " "%(prefix_chars)r" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1614 #, python-format msgid "dest= is required for options like %r" msgstr "dest= is vereist voor opties zoals %r" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1631 #, python-format msgid "invalid conflict_resolution value: %r" msgstr "ongeldige conflict_resolution waarde: %r" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1649 #, python-format msgid "conflicting option string: %s" msgid_plural "conflicting option strings: %s" msgstr[0] "conflicterende optietekenreeks: %s" msgstr[1] "conflicterende optietekenreeksen: %s" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1723 msgid "mutually exclusive arguments must be optional" msgstr "wederzijds exclusieve argumenten moeten facultatief zijn" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1799 msgid "positional arguments" msgstr "positionele argumenten" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1800 #, fuzzy msgid "options" msgstr "Uitvoeropties" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1815 msgid "show this help message and exit" msgstr "dit helpbericht weergeven en afsluiten" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1846 msgid "cannot have multiple subparser arguments" msgstr "kan niet meerdere subparserargumenten hebben" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:1898 #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2421 #, python-format msgid "unrecognized arguments: %s" msgstr "niet-herkende argumenten: %s" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2001 #, python-format msgid "not allowed with argument %s" msgstr "niet toegestaan met argument %s" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2043 #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2074 #, python-format msgid "ignored explicit argument %r" msgstr "genegeerd expliciet argument %r" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2181 #, python-format msgid "the following arguments are required: %s" msgstr "de volgende argumenten zijn vereist: %s" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2196 #, python-format msgid "one of the arguments %s is required" msgstr "een van de argumenten %s is vereist" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2240 msgid "expected one argument" msgstr "verwacht een argument" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2241 msgid "expected at most one argument" msgstr "verwacht hoogstens één argument" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2242 msgid "expected at least one argument" msgstr "verwacht ten minste één argument" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2246 #, python-format msgid "expected %s argument" msgid_plural "expected %s arguments" msgstr[0] "verwacht %s argument" msgstr[1] "verwachte %s argumenten" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2303 #, python-format msgid "ambiguous option: %(option)s could match %(matches)s" msgstr "dubbelzinnige optie: %(option)s kan overeenkomen met %(matches)s" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2364 #, python-format msgid "unexpected option string: %s" msgstr "onverwachte optiereeks: %s" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2566 #, python-format msgid "%r is not callable" msgstr "%r is niet oproepbaar" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2582 #, python-format msgid "invalid %(type)s value: %(value)r" msgstr "ongeldige %(type)s waarde: %(value)r" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2593 #, python-format msgid "invalid choice: %(value)r (choose from %(choices)s)" msgstr "ongeldige keuze: %(value)r (kies uit %(choices)s)" #: /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/argparse.py:2671 #, python-format msgid "%(prog)s: error: %(message)s\n" msgstr "%(prog)s: fout: %(message)s\n" #, python-format #~ msgid "Unreadable config file: %r" #~ msgstr "Onleesbaar config-bestand: %r" #~ msgid "The NNTP newsgroup could not be found." #~ msgstr "De NNTP-nieuwsgroep kon niet worden gevonden." #~ msgid "No NNTP server was specified, skipping this URL." #~ msgstr "" #~ "Er is geen NNTP-server opgegeven, waardoor deze URL is overgeslagen." #, python-format #~ msgid "Article number %(num)s found." #~ msgstr "Artikelnummer %(num)s gevonden." #, python-format #~ msgid "News group %(name)s found." #~ msgstr "Nieuwsgroep %(name)s gevonden." #~ msgid "No newsgroup specified in NNTP URL." #~ msgstr "Geen nieuwsgroep opgegeven in NNTP URL." #, python-format #~ msgid "NNTP server too busy; tried more than %d times." #~ msgstr "NNTP-server te druk; meer dan %d keer geprobeerd." #~ msgid "Host is empty" #~ msgstr "Host is leeg" #~ msgid "" #~ "Specify an NNTP server for 'news:...' links. Default is the\n" #~ "environment variable NNTP_SERVER. If no host is given,\n" #~ "only the syntax of the link is checked." #~ msgstr "" #~ "Geef een NNTP-server op voor 'nieuws:...' Verwijzigingen. Standaard is " #~ "de\n" #~ "omgevingsvariabele NNTP_SERVER. Als er geen host wordt gegeven,\n" #~ "alleen de syntaxis van de koppeling wordt gecontroleerd." #~ msgid "Default locale:" #~ msgstr "Standaard locale:" #~ msgid "optional arguments" #~ msgstr "optionele argumenten" linkchecker-10.5.0/pyoxidizer.bzl000066400000000000000000000005731466565367000170250ustar00rootroot00000000000000def make_exe(): dist = default_python_distribution() python_config = dist.make_python_interpreter_config() python_config.run_module = "linkcheck" exe = dist.to_python_executable( name="linkchecker", config=python_config, ) exe.add_python_resources(exe.pip_install([CWD])) return exe register_target("exe", make_exe) resolve_targets() linkchecker-10.5.0/pyproject.toml000066400000000000000000000067451466565367000170310ustar00rootroot00000000000000[project] name = "LinkChecker" dynamic = ["version"] description = "check links in web documents or full websites" readme = "README.rst" keywords = ["link", "url", "site", "checking", "crawling", "verification", "validation"] authors = [{name = "LinkChecker Authors"}] maintainers = [{name = "LinkChecker Authors"}] classifiers = [ "Topic :: Internet :: WWW/HTTP :: Site Management :: Link Checking", "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)", "Programming Language :: Python", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", ] requires-python = ">=3.9" dependencies = [ "requests >= 2.20", "dnspython >= 2.0", "beautifulsoup4 >= 4.8.1", ] [build-system] requires = [ "hatchling >= 1.8.0", "hatch-vcs", "setuptools-scm >= 7.1.0", ] build-backend = "hatchling.build" [project.urls] Homepage = "https://linkchecker.github.io/linkchecker/" "Bug Tracker" = "https://github.com/linkchecker/linkchecker/issues" Repository = "https://github.com/linkchecker/linkchecker" Changelog = "https://github.com/linkchecker/linkchecker/blob/master/doc/changelog.txt" [project.scripts] linkchecker = "linkcheck.command.linkchecker:linkchecker" [tool.hatch.build] artifacts = [ "linkcheck/_release.py", "linkcheck/data/locale", ] exclude = [ ".github", ".gitattributes", ] [tool.hatch.build.hooks.custom] path = "tools/hatch_build.py" [tool.hatch.build.targets.sdist] strict-naming = false [tool.hatch.build.targets.wheel] only-include = ["linkcheck"] strict-naming = false [tool.hatch.build.targets.wheel.shared-data] "doc/man/en/linkchecker.1" = "share/man/man1/linkchecker.1" "doc/man/en/linkcheckerrc.5" = "share/man/man5/linkcheckerrc.5" "doc/man/de/linkchecker.1" = "share/man/de/man1/linkchecker.1" "doc/man/de/linkcheckerrc.5" = "share/man/de/man5/linkcheckerrc.5" "cgi-bin/lconline/leer.html.en" = "share/linkchecker/examples/cgi-bin/lconline/leer.html.en" "cgi-bin/lconline/leer.html.de" = "share/linkchecker/examples/cgi-bin/lconline/leer.html.de" "cgi-bin/lconline/index.html" = "share/linkchecker/examples/cgi-bin/lconline/index.html" "cgi-bin/lconline/lc_cgi.html.en" = "share/linkchecker/examples/cgi-bin/lconline/lc_cgi.html.en" "cgi-bin/lconline/lc_cgi.html.de" = "share/linkchecker/examples/cgi-bin/lconline/lc_cgi.html.de" "cgi-bin/lconline/check.js" = "share/linkchecker/examples/cgi-bin/lconline/check.js" "cgi-bin/lc.wsgi" = "share/linkchecker/examples/cgi-bin/lc.wsgi" "config/create.sql" = "share/linkchecker/examples/config/create.sql" "config/linkchecker.apache2.conf" = "share/linkchecker/examples/config/linkchecker.apache2.conf" "config/linkchecker-completion" = "share/linkchecker/examples/config/linkchecker-completion" "doc/examples/check_failures.sh" = "share/linkchecker/examples/check_failures.sh" "doc/examples/check_for_x_errors.sh" = "share/linkchecker/examples/check_for_x_errors.sh" "doc/examples/check_urls.sh" = "share/linkchecker/examples/check_urls.sh" [tool.hatch.version] source = "vcs" [tool.hatch.version.raw-options] local_scheme = "node-and-timestamp" version_scheme = "post-release" [tool.hatch.envs.test] dependencies = [ "cryptography", "pdfminer.six", "pyftpdlib", "pyopenssl", "pytest", "pytest-xdist", ] [tool.hatch.envs.test.scripts] tests = "pytest -vra tests" linkchecker-10.5.0/pytest-minreqs.ini000066400000000000000000000001441466565367000176050ustar00rootroot00000000000000# This file is needed until minimum bs4 >= 4.11 [pytest] testpaths = tests addopts = -ra --tb=short linkchecker-10.5.0/pytest.ini000066400000000000000000000002421466565367000161300ustar00rootroot00000000000000[pytest] testpaths = tests addopts = -ra --tb=short filterwarnings = ignore::bs4.MarkupResemblesLocatorWarning ignore::bs4.builder.XMLParsedAsHTMLWarning linkchecker-10.5.0/requirements-min.txt000066400000000000000000000002041466565367000201420ustar00rootroot00000000000000# required: beautifulsoup4 == 4.8.1 requests == 2.20.0 dnspython == 2.0.0 # optional: argcomplete == 1.8.1 pdfminer.six == 20181108 linkchecker-10.5.0/requirements.txt000066400000000000000000000002001466565367000173550ustar00rootroot00000000000000# required: beautifulsoup4 >= 4.8.1 requests >= 2.20 dnspython >= 2.0 # optional: argcomplete >= 1.8.1 pdfminer.six >= 20181108 linkchecker-10.5.0/robots.txt000066400000000000000000000006031466565367000161510ustar00rootroot00000000000000# A test robots.txt file. It resides in the root directory to be found # by the unittest HTTP server. # Note that while unit tests are running, the contents of this file # can change. User-agent: LinkChecker Crawl-delay: 1 Disallow: /secret # a comment line inside a rule, followed by non-ascii Disallow: /umlaut/ö # The following rule should not match User-agent: * Crawl-delay: 100 linkchecker-10.5.0/scripts/000077500000000000000000000000001466565367000155705ustar00rootroot00000000000000linkchecker-10.5.0/scripts/analyze_memdump.py000077500000000000000000000076171466565367000213470ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (C) 2012-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Analyze a memory dump by the meliae module. """ import sys import os import codecs import html from linkcheck import strformat def main(filename): om = print_memorydump(filename) dirname, basename = os.path.split(filename) basename = os.path.splitext(basename)[0] basedir = os.path.join(dirname, basename) if not os.path.isdir(basedir): os.mkdir(basedir) write_htmlfiles(om, basedir) def print_memorydump(filename): from meliae import loader om = loader.load(filename, collapse=True) om.remove_expensive_references() print(om.summarize()) return om def write_htmlfiles(om, basedir): om.compute_parents() open_files = {} for obj in om.objs.itervalues(): fp = get_file(obj.type_str, open_files, basedir) write_html_obj(fp, obj, om.objs) close_files(open_files) def get_file(type_str, open_files, basedir): """Get already opened file, or open and initialize a new one.""" if type_str not in open_files: filename = type_str + ".html" encoding = "utf-8" fd = codecs.open(os.path.join(basedir, filename), "w", encoding) open_files[type_str] = fd write_html_header(fd, type_str, encoding) return open_files[type_str] def close_files(open_files): for fp in open_files.values(): write_html_footer(fp) fp.close() HtmlHeader = """ """ def write_html_header(fp, type_str, encoding): fp.write(HtmlHeader % encoding) fp.write("

Type %s

\n" % type_str) fp.write( "" "\n" ) def get_children(obj, objs): res = [] for address in obj.children: if address in objs: child = objs[address] url = "#%d" % address if child.type_str != obj.type_str: url = child.type_str + ".html" + url entry = '%d' % (url, address) else: entry = "%d" % address res.append(entry) return res def get_parents(obj, objs): res = [] for address in obj.parents: if address in objs: parent = objs[address] url = "#%d" % address if parent.type_str != obj.type_str: url = parent.type_str + ".html" + url entry = '%d' % (url, address) else: entry = "%d" % address res.append(entry) return res def write_html_obj(fp, obj, objs): if obj.value is None: value = "None" else: value = html.escape(str(obj.value)) attrs = dict( address=obj.address, size=strformat.strsize(obj.size), children=",".join(get_children(obj, objs)), parents=",".join(get_parents(obj, objs)), value=value, ) fp.write( "" "\n" % attrs ) def write_html_footer(fp): fp.write("
AddressNameSizeParentsReferences
%(address)d%(value)s%(size)s%(children)s
") if __name__ == "__main__": filename = sys.argv[1] main(filename) linkchecker-10.5.0/scripts/nodebug.sh000077500000000000000000000002721466565367000175530ustar00rootroot00000000000000#!/bin/sh # deactivate all debug calls set -e set -u d=$(dirname $0) base=$(readlink -f $d/../linkcheck) find "$base" -type f -print0 | xargs -0 sed -i 's/ log.debug(/ #log.debug(/g' linkchecker-10.5.0/scripts/removeafter.py000077500000000000000000000006621466565367000204700ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (C) 2012-2014 Bastian Kleineidam """Remove all lines after a given marker line. """ import fileinput import sys def main(args): """Remove lines after marker.""" filename = args[0] marker = args[1] for line in fileinput.input(filename, inplace=1): print(line.rstrip()) if line.startswith(marker): break if __name__ == "__main__": main(sys.argv[1:]) linkchecker-10.5.0/scripts/update_iana_uri_schemes.py000066400000000000000000000060261466565367000230060ustar00rootroot00000000000000import sys import re import csv import requests iana_uri_schemes = "https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml" # CSV format: URI Scheme,Template,Description,Status,Well-Known URI Support,Reference,Notes csv_iana_uri_schemes = ( "https://www.iana.org/assignments/uri-schemes/uri-schemes-1.csv" ) iana_uri_schemes_dict = {} iana_uri_schemes_other = { "clsid": "Microsoft specific", "find": "Mozilla specific", "gemini": "Gemini protocol", "isbn": "ISBN (int. book numbers)", "javascript": "JavaScript", "ms-windows-store": "Microsoft Store", "slack": "Slack Technologies client", "tg": "Telegram", "whatsapp": "WhatsApp", } filter_uri_schemes_permanent = ( "file", "ftp", "http", "https", "mailto", ) template = ''' # from %(uri)s ignored_schemes_permanent = r""" %(permanent)s """ ignored_schemes_provisional = r""" %(provisional)s """ ignored_schemes_historical = r""" %(historical)s """ ignored_schemes_other = r""" %(other)s """ ignored_schemes = "^({}{}{}{})$".format( ignored_schemes_permanent, ignored_schemes_provisional, ignored_schemes_historical, ignored_schemes_other, ) ignored_schemes_re = re.compile(ignored_schemes, re.VERBOSE) is_unknown_scheme = ignored_schemes_re.match ''' def main(args): parse_csv_file(csv_iana_uri_schemes, iana_uri_schemes_dict) for scheme in iana_uri_schemes_other: if ( scheme in iana_uri_schemes_dict["Permanent"] or scheme in iana_uri_schemes_dict["Provisional"] or scheme in iana_uri_schemes_dict["Historical"] ): raise ValueError(scheme) for scheme in filter_uri_schemes_permanent: if scheme in iana_uri_schemes_dict["Permanent"]: del iana_uri_schemes_dict["Permanent"][scheme] args = dict( uri=iana_uri_schemes, permanent=get_regex(iana_uri_schemes_dict["Permanent"]), provisional=get_regex(iana_uri_schemes_dict["Provisional"]), historical=get_regex(iana_uri_schemes_dict["Historical"]), other=get_regex(iana_uri_schemes_other), ) res = template % args print(res.rstrip()) return 0 def get_regex(schemes): expr = [ f"|{re.escape(scheme).ljust(10)} # {description}" for scheme, description in sorted(schemes.items()) ] return "\n".join(expr) def parse_csv_file(url, res): """Parse given URL and write res with {scheme -> description}""" response = requests.get(url, stream=True) reader = csv.reader(response.iter_lines(decode_unicode=True)) first_row = True for row in reader: if first_row: # skip first row first_row = False else: scheme, template, description, status, urisupport, reference, notes = row scheme = scheme.replace(" (OBSOLETE)", "") # remove the HTTP historic experiments flag if status not in res: res[status] = {} res[status][scheme] = description if __name__ == "__main__": sys.exit(main(sys.argv[1:])) linkchecker-10.5.0/scripts/update_iana_uri_schemes.sh000077500000000000000000000004441466565367000227710ustar00rootroot00000000000000#!/bin/bash # Update the list of unknown and therefore ignored URL schemes. set -o nounset set -o errexit set -o pipefail #set -o xtrace target=linkcheck/checker/unknownurl.py python scripts/removeafter.py "$target" "# DO NOT REMOVE" python scripts/update_iana_uri_schemes.py >> "$target" linkchecker-10.5.0/scripts/viewprof.py000077500000000000000000000004211466565367000200030ustar00rootroot00000000000000#!/usr/bin/env python """ View yappi profiling data. Usage: $0 """ import sys import yappi def main(args): filename = args[0] stats = yappi.YFuncStats() stats.add(filename) stats.print_all() if __name__ == "__main__": main(sys.argv[1:]) linkchecker-10.5.0/tests/000077500000000000000000000000001466565367000152435ustar00rootroot00000000000000linkchecker-10.5.0/tests/__init__.py000066400000000000000000000155371466565367000173670ustar00rootroot00000000000000# Copyright (C) 2005-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. import signal import subprocess import os import sys import socket import unittest import pytest from contextlib import contextmanager from functools import lru_cache, wraps from linkcheck import init_i18n, LinkCheckerInterrupt class TestBase(unittest.TestCase): """ Base class for tests. """ def setUp(self): """Ensure the current locale setting is the default. Otherwise, warnings will get translated and will break tests.""" super().setUp() os.environ["LANG"] = "C" init_i18n() @lru_cache(1) def running_in_ci(): return "CI" in os.environ def skip(reason, strict=True): if strict and running_in_ci(): pytest.fail(reason) else: pytest.skip(reason) def run(cmd, verbosity=0, **kwargs): """Run command without error checking. @return: command return code""" if kwargs.get("shell"): # for shell calls the command must be a string cmd = " ".join(cmd) return subprocess.call(cmd, **kwargs) def run_checked(cmd, ret_ok=(0,), **kwargs): """Run command and raise OSError on error.""" retcode = run(cmd, **kwargs) if retcode not in ret_ok: msg = "Command `%s' returned non-zero exit status %d" % (cmd, retcode) raise OSError(msg) return retcode def run_silent(cmd): """Run given command without output.""" null = open(os.name == "nt" and ":NUL" or "/dev/null", "w") try: return run(cmd, stdout=null, stderr=subprocess.STDOUT) finally: null.close() def _need_func(testfunc, name, strict=True): """Decorator skipping test if given testfunc fails.""" def check_func(func): @wraps(func) def newfunc(*args, **kwargs): if not testfunc(): skip("%s is not available" % name, strict) return func(*args, **kwargs) return newfunc return check_func @lru_cache(1) def has_network(): """Test if network is up.""" try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("www.python.org", 80)) s.close() return True except Exception: pass return False need_network = _need_func(has_network, "network") @lru_cache(1) def has_msgfmt(): """Test if msgfmt is available.""" return run_silent(["msgfmt", "-V"]) == 0 need_msgfmt = _need_func(has_msgfmt, "msgfmt") @lru_cache(1) def has_posix(): """Test if this is a POSIX system.""" return os.name == "posix" need_posix = _need_func(has_posix, "POSIX system", False) @lru_cache(1) def has_windows(): """Test if this is a Windows system.""" return os.name == "nt" need_windows = _need_func(has_windows, "Windows system", False) @lru_cache(1) def has_linux(): """Test if this is a Linux system.""" return sys.platform.startswith("linux") need_linux = _need_func(has_linux, "Linux system", False) @lru_cache(1) def has_clamav(): """Test if ClamAV daemon is installed and running.""" try: cmd = ["grep", "LocalSocket", "/etc/clamav/clamd.conf"] sock = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0].split()[1] if sock: s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.connect(sock) s.close() return True except Exception: pass return False need_clamav = _need_func(has_clamav, "ClamAV") @lru_cache(1) def has_proxy(): """Test if proxy is running on port 8081.""" try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("localhost", 8081)) s.close() return True except Exception: return False need_proxy = _need_func(has_proxy, "proxy") @lru_cache(1) def has_pyftpdlib(): """Test if pyftpdlib is available.""" try: import pyftpdlib return True except ImportError: return False need_pyftpdlib = _need_func(has_pyftpdlib, "pyftpdlib") @lru_cache(1) def has_x11(): """Test if DISPLAY variable is set.""" return os.getenv("DISPLAY") is not None need_x11 = _need_func(has_x11, "X11") @lru_cache(1) def has_geoip(): from linkcheck.plugins import locationinfo return locationinfo.geoip is not None need_geoip = _need_func(has_geoip, "geoip") @lru_cache(1) def has_word(): """Test if Word is available.""" from linkcheck.plugins import parseword return parseword.has_word() need_word = _need_func(has_word, "Word", False) @lru_cache(1) def has_pdflib(): from linkcheck.plugins import parsepdf return parsepdf.has_pdflib need_pdflib = _need_func(has_pdflib, "pdflib") @contextmanager def _limit_time(seconds): """Raises LinkCheckerInterrupt if given number of seconds have passed.""" if os.name == "posix": def signal_handler(signum, frame): raise LinkCheckerInterrupt("timed out") old_handler = signal.getsignal(signal.SIGALRM) signal.signal(signal.SIGALRM, signal_handler) signal.alarm(seconds) yield if os.name == "posix": signal.alarm(0) if old_handler is not None: signal.signal(signal.SIGALRM, old_handler) def limit_time(seconds, skip=False): """Limit test time to the given number of seconds, else fail or skip.""" def run_limited(func): def new_func(*args, **kwargs): try: with _limit_time(seconds): return func(*args, **kwargs) except LinkCheckerInterrupt as msg: if skip: pytest.skip("time limit of %d seconds exceeded" % seconds) assert False, msg new_func.__name__ = func.__name__ return new_func return run_limited def get_file(filename=None): """ Get file name located within 'data' directory. """ directory = os.path.join("tests", "checker", "data") if filename: return os.path.join(directory, filename) return directory if __name__ == "__main__": print("has clamav", has_clamav()) print("has network", has_network()) print("has msgfmt", has_msgfmt()) print("has POSIX", has_posix()) print("has proxy", has_proxy()) print("has X11", has_x11()) linkchecker-10.5.0/tests/cache/000077500000000000000000000000001466565367000163065ustar00rootroot00000000000000linkchecker-10.5.0/tests/cache/__init__.py000066400000000000000000000000001466565367000204050ustar00rootroot00000000000000linkchecker-10.5.0/tests/cache/test_urlqueue.py000066400000000000000000000134351466565367000215740ustar00rootroot00000000000000# Copyright (C) 2017 Petr Dlouhý # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. import unittest from collections import namedtuple import linkcheck.configuration from linkcheck.cache.results import ResultCache from linkcheck.cache.urlqueue import Empty, NUM_PUTS_CLEANUP, UrlQueue UrlData = namedtuple("UrlData", "url cache_url aggregate has_result") Aggregate = namedtuple("Aggregate", "result_cache") class TestUrlQueue(unittest.TestCase): def setUp(self): config = linkcheck.configuration.Configuration() self.result_cache = ResultCache(config["resultcachesize"]) self.urlqueue = UrlQueue() self.urldata1 = UrlData( url="Foo", cache_url="Foo", aggregate=Aggregate(result_cache=self.result_cache), has_result=True, ) def test_max_allowed_urls_bad_value(self): with self.assertRaises(ValueError): UrlQueue(max_allowed_urls=0) with self.assertRaises(ValueError): UrlQueue(max_allowed_urls=-1) def test_qsize(self): """ Test qsize() """ self.assertEqual(self.urlqueue.qsize(), 0) self.urlqueue.put(self.urldata1) self.assertEqual(self.urlqueue.qsize(), 1) def test_empty(self): """ Test empty() """ self.assertEqual(self.urlqueue.empty(), True) self.urlqueue.put(self.urldata1) self.assertEqual(self.urlqueue.empty(), False) def test_get_empty(self): """ Test, that get() with empty queue throws Empty """ with self.assertRaises(Empty): self.assertEqual(self.urlqueue.get(0), None) def test_get_negative_timeout(self): """ Test, that get() with negative timeout throws ValueError """ with self.assertRaises(ValueError): self.assertEqual(self.urlqueue.get(-1), None) def test_put_get(self): """ Test, that after put() we can get() the item and it can be get only once """ self.urlqueue.put(self.urldata1) cached_item = self.result_cache.get_result(self.urldata1) self.assertEqual(cached_item, None) self.assertEqual(self.urlqueue.get(), self.urldata1) with self.assertRaises(Empty): self.assertEqual(self.urlqueue.get(0), None) def test_put_has_result_false(self): """ Test, that element with has_result=False is put() on the end of queue """ self.urlqueue.put(self.urldata1) urldata = UrlData( url="Bar", cache_url="Bar", aggregate=Aggregate(result_cache=self.result_cache), has_result=False, ) self.urlqueue.put(urldata) self.assertEqual(self.urlqueue.get(), self.urldata1) self.assertEqual(self.urlqueue.get(), urldata) with self.assertRaises(Empty): self.assertEqual(self.urlqueue.get(0), None) def test_put_has_result_true(self): """ Test, that element with has_result=True is put() on the beginning of queue """ self.urlqueue.put(self.urldata1) urldata = UrlData( url="Bar", cache_url="Bar", aggregate=Aggregate(result_cache=self.result_cache), has_result=True, ) self.urlqueue.put(urldata) self.assertEqual(self.urlqueue.get(), urldata) self.assertEqual(self.urlqueue.get(), self.urldata1) with self.assertRaises(Empty): self.assertEqual(self.urlqueue.get(0), None) def test_put_cache(self): """ Test, that making put() on two elements with same cache_url adds only one element """ self.urlqueue.put(self.urldata1) urldata = UrlData( url="Bar", cache_url="Foo", aggregate=Aggregate(result_cache=self.result_cache), has_result=True, ) self.urlqueue.put(urldata) self.assertEqual(self.urlqueue.qsize(), 1) self.assertEqual(self.urlqueue.get(), self.urldata1) with self.assertRaises(Empty): self.assertEqual(self.urlqueue.get(0), None) def test_cleanup(self): """ Test, that after adding NUM_PUTS_CLEANUP elements the queue is cleaned up. Whether the cleanup is was performed is determined, that element in cache is now on top of the queue. """ for i in range(NUM_PUTS_CLEANUP - 1): self.urlqueue.put( UrlData( url="Bar", cache_url="Bar address %s" % i, aggregate=Aggregate(result_cache=self.result_cache), has_result=False, ), ) self.assertEqual(self.urlqueue.qsize(), NUM_PUTS_CLEANUP - 1) urldata = UrlData( url="Bar", cache_url="Bar address", aggregate=Aggregate(result_cache=self.result_cache), has_result=False, ) self.result_cache.add_result("Bar address 2", "asdf") self.urlqueue.put(urldata) self.assertEqual(self.urlqueue.qsize(), NUM_PUTS_CLEANUP) self.assertEqual(self.urlqueue.get().cache_url, "Bar address 2") linkchecker-10.5.0/tests/checker/000077500000000000000000000000001466565367000166475ustar00rootroot00000000000000linkchecker-10.5.0/tests/checker/__init__.py000066400000000000000000000250111466565367000207570ustar00rootroot00000000000000# Copyright (C) 2004-2014 Bastian Kleineidam # # 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 of the License, or # (at your option) any later 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. """ Define standard test support classes functional for LinkChecker tests. """ import os import re import difflib import linkcheck.checker import linkcheck.configuration import linkcheck.director import linkcheck.logger from .. import get_file, TestBase # helper alias get_url_from = linkcheck.checker.get_url_from class TestLogger(linkcheck.logger._Logger): """ Output logger for automatic regression tests. """ # don't attempt to collect this class because it has an __init__() __test__ = False LoggerName = "test" logparts = [ "cachekey", "realurl", "name", "base", "info", "warning", "result", "url", ] def __init__(self, **kwargs): """ The kwargs must have "expected" keyword with the expected logger output lines. """ args = self.get_args(kwargs) args["parts"] = self.logparts super().__init__(**args) # list of expected output lines self.expected = args["expected"] # list of real output lines self.result = [] # diff between expected and real output self.diff = [] def normalize(self, result_log): # XXX we assume that each log entry has a URL key, # maybe we should add an assert into log_url() to that effect? # Ensure that log entries are sorted by URL key: # - join the result_log items together # - split into entries (starting with a URL key) # - sort the entries and join together # - split the entries back into a list return "\n".join( sorted( [ "url %s" % x.strip() for x in re.split( r"^url ", "\n".join(result_log), flags=re.DOTALL | re.MULTILINE, ) if x ] ) ).splitlines() def start_output(self): """ Nothing to do here. """ pass def log_url(self, url_data): """ Append logger output to self.result. """ if self.has_part("url"): url = "url %s" % url_data.base_url self.result.append(url) if self.has_part("cachekey"): cache_key = url_data.cache_url if url_data.cache_url else None self.result.append("cache key %s" % cache_key) if self.has_part("realurl"): self.result.append("real url %s" % url_data.url) if self.has_part("name") and url_data.name: self.result.append("name %s" % url_data.name) if self.has_part("base") and url_data.base_ref: self.result.append("baseurl %s" % url_data.base_ref) if self.has_part("info"): for info in url_data.info: if ( "Last modified" not in info and "is located in" not in info ): self.result.append("info %s" % info) if self.has_part("warning"): for tag, warning in url_data.warnings: self.result.append("warning %s" % warning) if self.has_part("result"): self.result.append("valid" if url_data.valid else "error") if self.has_part("line"): self.result.append("line %s" % url_data.line) if self.has_part("col"): self.result.append("col %s" % url_data.column) if self.has_part("size"): self.result.append("size %s" % url_data.size) if self.has_part("parent_url"): self.result.append("parent_url %s" % url_data.parent_url) if self.has_part("page"): self.result.append("page %s" % url_data.page) if self.has_part("modified"): self.result.append("modified %s" % url_data.modified) if self.has_part("content_type"): self.result.append("content_type %s" % url_data.content_type) # note: do not append url_data.result since this is # platform dependent def end_output(self, linknumber=-1, **kwargs): """ Stores differences between expected and result in self.diff. """ self.expected = self.normalize(self.expected) self.result = self.normalize(self.result) self.diff = list( difflib.unified_diff( self.expected, self.result, fromfile="expected", tofile="result", lineterm="", ) ) def get_file_url(filename): return re.sub("^([a-zA-Z]):", r"/\1|", filename.replace("\\", "/")) def add_fileoutput_config(config): if os.name == "posix": devnull = "/dev/null" elif os.name == "nt": devnull = "NUL" else: return for ftype in linkcheck.logger.LoggerNames: if ftype in ("test", "failures"): continue logger = config.logger_new(ftype, fileoutput=1, filename=devnull) config["fileoutput"].append(logger) def get_test_aggregate(confargs, logargs, logger=TestLogger): """Initialize a test configuration object.""" config = linkcheck.configuration.Configuration() config.logger_add(logger) config["recursionlevel"] = 1 config["logger"] = config.logger_new(logger.LoggerName, **logargs) add_fileoutput_config(config) config["verbose"] = True config["threads"] = 0 config["status"] = False config["checkextern"] = True config.update(confargs) config.sanitize() return linkcheck.director.get_aggregate(config) class LinkCheckTest(TestBase): """ Functional test class with ability to test local files. """ logger = TestLogger def norm(self, url, encoding="utf-8"): """Helper function to norm a url.""" return linkcheck.url.url_norm(url, encoding=encoding)[0] def get_attrs(self, **kwargs): """Return current and data directory as dictionary. You can augment the dict with keyword attributes.""" d = { "curdir": get_file_url(os.getcwd()), "datadir": "tests/checker/data", } d.update(kwargs) return d def get_resultlines(self, filename): """ Return contents of file, as list of lines without line endings, ignoring empty lines and lines starting with a hash sign (#). """ resultfile = get_file("%s.result" % filename) d = { "curdir": get_file_url(os.getcwd()), "datadir": get_file_url(get_file()), } # the webserver uses the first free port number if hasattr(self, "port"): d["port"] = self.port # all result files are encoded in utf-8 with open(resultfile, encoding="utf-8") as f: return [ line.rstrip("\r\n") % d for line in f if line.strip() and not line.startswith("#") ] def get_url(self, filename): """Get URL for given filename.""" return get_file(filename) def file_test(self, filename, confargs=None): """Check with expected result in .result.""" url = self.get_url(filename) if confargs is None: confargs = {} logargs = {"expected": self.get_resultlines(filename)} aggregate = get_test_aggregate(confargs, logargs, logger=self.logger) url_data = get_url_from(url, 0, aggregate, extern=(0, 0)) aggregate.urlqueue.put(url_data) linkcheck.director.check_urls(aggregate) logger = aggregate.config["logger"] diff = logger.diff if diff: msg = os.linesep.join([url] + diff) self.fail(msg) if logger.stats.internal_errors: self.fail("%d internal errors occurred!" % logger.stats.internal_errors) def direct( self, url, resultlines, parts=None, recursionlevel=0, confargs=None, url_encoding=None, ): """Check url with expected result.""" assert isinstance(url, str), repr(url) if confargs is None: confargs = {"recursionlevel": recursionlevel} else: confargs["recursionlevel"] = recursionlevel logargs = {"expected": resultlines} if parts is not None: logargs["parts"] = parts aggregate = get_test_aggregate(confargs, logargs) # initial URL has recursion level zero url_reclevel = 0 url_data = get_url_from(url, url_reclevel, aggregate, url_encoding=url_encoding) aggregate.urlqueue.put(url_data) linkcheck.director.check_urls(aggregate) logger = aggregate.config["logger"] diff = logger.diff if diff: d = ["Differences found testing %s" % url] d.extend(x.rstrip() for x in diff[2:]) self.fail(os.linesep.join(d)) if logger.stats.internal_errors: self.fail("%d internal errors occurred!" % logger.stats.internal_errors) class MailTest(LinkCheckTest): """Test mailto: link checking.""" def mail_valid(self, addr, **kwargs): """Test valid mail address.""" return self.mail_test(addr, "valid", **kwargs) def mail_error(self, addr, **kwargs): """Test error mail address.""" return self.mail_test(addr, "error", **kwargs) def mail_test(self, addr, result, encoding="utf-8", cache_key=None, warning=None): """Test mail address.""" url = self.norm(addr, encoding=encoding) if cache_key is None: cache_key = url resultlines = [ "url %s" % url, "cache key %s" % cache_key, "real url %s" % url, ] if warning: resultlines.append("warning %s" % warning) resultlines.append(result) self.direct(url, resultlines) linkchecker-10.5.0/tests/checker/data/000077500000000000000000000000001466565367000175605ustar00rootroot00000000000000linkchecker-10.5.0/tests/checker/data/Bookmarks000066400000000000000000000012511466565367000214320ustar00rootroot00000000000000{ "checksum": "b1135bffd7fb303459b60851e3f800eb", "roots": { "bookmark_bar": { "children": [ { "date_added": "12942261620096544", "id": "3", "name": "Testlink", "type": "url", "url": "http://example.com/" } ], "date_added": "0", "date_modified": "12942261620096544", "id": "1", "name": "Bookmarks Bar", "type": "folder" }, "other": { "children": [ ], "date_added": "0", "date_modified": "0", "id": "2", "name": "Other Bookmarks", "type": "folder" } }, "version": 1 } linkchecker-10.5.0/tests/checker/data/Bookmarks.result000066400000000000000000000004301466565367000227450ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/Bookmarks cache key file://%(curdir)s/%(datadir)s/Bookmarks real url file://%(curdir)s/%(datadir)s/Bookmarks name %(datadir)s/Bookmarks valid url http://example.com/ cache key http://example.com/ real url http://example.com/ name Testlink valid linkchecker-10.5.0/tests/checker/data/a b/000077500000000000000000000000001466565367000202025ustar00rootroot00000000000000linkchecker-10.5.0/tests/checker/data/a b/el.html000066400000000000000000000000421466565367000214640ustar00rootroot00000000000000External link linkchecker-10.5.0/tests/checker/data/a b/t.txt000066400000000000000000000000021466565367000211760ustar00rootroot00000000000000 linkchecker-10.5.0/tests/checker/data/all_parts_linenos.html000066400000000000000000000002701466565367000241550ustar00rootroot00000000000000 linkchecker-10.5.0/tests/checker/data/all_parts_linenos.html.result000066400000000000000000000014041466565367000254720ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/all_parts_linenos.html cache key file://%(curdir)s/%(datadir)s/all_parts_linenos.html real url file://%(curdir)s/%(datadir)s/all_parts_linenos.html name %(datadir)s/all_parts_linenos.html valid line None col None size 184 parent_url page 0 content_type text/html url base2.html cache key file://%(curdir)s/%(datadir)s/base2.html real url file://%(curdir)s/%(datadir)s/base2.html valid line 4 col 1 size 64 parent_url file://%(curdir)s/%(datadir)s/all_parts_linenos.html page 0 content_type text/html url file.html cache key file://%(curdir)s/%(datadir)s/file.html real url file://%(curdir)s/%(datadir)s/file.html valid line 6 col 1 size 115 parent_url file://%(curdir)s/%(datadir)s/all_parts_linenos.html page 0 content_type text/html linkchecker-10.5.0/tests/checker/data/anchor.html000066400000000000000000000000331466565367000217140ustar00rootroot00000000000000
linkchecker-10.5.0/tests/checker/data/anchor1.html000066400000000000000000000004621466565367000220030ustar00rootroot00000000000000
one one one two one three one four anchor1 one from 1 anchor2 two from 1 anchor2 three from 1 linkchecker-10.5.0/tests/checker/data/anchor1.html.result000066400000000000000000000043061466565367000233210ustar00rootroot00000000000000url #twofour cache key file://%(curdir)s/%(datadir)s/anchor2.html#twofour real url file://%(curdir)s/%(datadir)s/anchor2.html#twofour name anchor2 four from 2 valid url #threefour cache key file://%(curdir)s/%(datadir)s/anchor3.html#threefour real url file://%(curdir)s/%(datadir)s/anchor3.html#threefour name anchor3 four from 3 valid url #oneone cache key file://%(curdir)s/%(datadir)s/anchor1.html#oneone real url file://%(curdir)s/%(datadir)s/anchor1.html#oneone name anchor1 one from 1 valid url #twoone cache key file://%(curdir)s/%(datadir)s/anchor2.html#twoone real url file://%(curdir)s/%(datadir)s/anchor2.html#twoone name anchor2 one from 2 valid url #threeone cache key file://%(curdir)s/%(datadir)s/anchor3.html#threeone real url file://%(curdir)s/%(datadir)s/anchor3.html#threeone name anchor3 one from 3 valid url anchor1.html#onefour cache key file://%(curdir)s/%(datadir)s/anchor1.html#onefour real url file://%(curdir)s/%(datadir)s/anchor1.html#onefour name anchor1 four from 3 valid url anchor1.html#onethree cache key file://%(curdir)s/%(datadir)s/anchor1.html#onethree real url file://%(curdir)s/%(datadir)s/anchor1.html#onethree name anchor1 three from 3 valid url anchor1.html#onetwo cache key file://%(curdir)s/%(datadir)s/anchor1.html#onetwo real url file://%(curdir)s/%(datadir)s/anchor1.html#onetwo name anchor1 two from 3 valid url anchor2.html#twothree cache key file://%(curdir)s/%(datadir)s/anchor2.html#twothree real url file://%(curdir)s/%(datadir)s/anchor2.html#twothree name anchor2 three from 1 valid url anchor2.html#twotwo cache key file://%(curdir)s/%(datadir)s/anchor2.html#twotwo real url file://%(curdir)s/%(datadir)s/anchor2.html#twotwo name anchor2 two from 1 valid url anchor3.html#threethree cache key file://%(curdir)s/%(datadir)s/anchor3.html#threethree real url file://%(curdir)s/%(datadir)s/anchor3.html#threethree name anchor3 three from 2 valid url anchor3.html#threetwo cache key file://%(curdir)s/%(datadir)s/anchor3.html#threetwo real url file://%(curdir)s/%(datadir)s/anchor3.html#threetwo name anchor3 two from 2 valid url file://%(curdir)s/%(datadir)s/anchor1.html cache key file://%(curdir)s/%(datadir)s/anchor1.html real url file://%(curdir)s/%(datadir)s/anchor1.html valid linkchecker-10.5.0/tests/checker/data/anchor2.html000066400000000000000000000006261466565367000220060ustar00rootroot00000000000000 two one two two two three two four <-- links --> anchor2 one from 2 anchor3 two from 2 anchor3 three from 2 anchor2 four from 2 anchor1 one from 2 linkchecker-10.5.0/tests/checker/data/anchor3.html000066400000000000000000000006501466565367000220040ustar00rootroot00000000000000 three one three two three three three four <-- links --> anchor3 one from 3 anchor1 two from 3 anchor1 three from 3 anchor3 four from 3 anchor1 four from 3 linkchecker-10.5.0/tests/checker/data/archive.html000066400000000000000000000001321466565367000220630ustar00rootroot00000000000000 linkchecker-10.5.0/tests/checker/data/archive.html.result000066400000000000000000000006271466565367000234110ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/archive.html cache key file://%(curdir)s/%(datadir)s/archive.html real url file://%(curdir)s/%(datadir)s/archive.html name %(datadir)s/archive.html valid url file.html cache key file://%(curdir)s/%(datadir)s/file.html real url file://%(curdir)s/%(datadir)s/file.html valid url http://www.example.com cache key http://www.example.com real url http://www.example.com valid linkchecker-10.5.0/tests/checker/data/base/000077500000000000000000000000001466565367000204725ustar00rootroot00000000000000linkchecker-10.5.0/tests/checker/data/base/test.txt000066400000000000000000000000001466565367000222000ustar00rootroot00000000000000linkchecker-10.5.0/tests/checker/data/base1.html000066400000000000000000000002701466565367000214400ustar00rootroot00000000000000 linkchecker-10.5.0/tests/checker/data/base1.html.result000066400000000000000000000006471466565367000227650ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/base1.html cache key file://%(curdir)s/%(datadir)s/base1.html real url file://%(curdir)s/%(datadir)s/base1.html name %(datadir)s/base1.html valid url base2.html cache key file://%(curdir)s/%(datadir)s/base2.html real url file://%(curdir)s/%(datadir)s/base2.html valid url file.html cache key file://%(curdir)s/%(datadir)s/file.html real url file://%(curdir)s/%(datadir)s/file.html valid linkchecker-10.5.0/tests/checker/data/base2.html000066400000000000000000000001001466565367000214310ustar00rootroot00000000000000 linkchecker-10.5.0/tests/checker/data/base2.html.result000066400000000000000000000005751466565367000227660ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/base2.html cache key file://%(curdir)s/%(datadir)s/base2.html real url file://%(curdir)s/%(datadir)s/base2.html name %(datadir)s/base2.html valid url test.txt cache key file://%(curdir)s/%(datadir)s/base/test.txt real url file://%(curdir)s/%(datadir)s/base/test.txt baseurl file://%(curdir)s/%(datadir)s/base/ warning Content size is zero. valid linkchecker-10.5.0/tests/checker/data/base3.html000066400000000000000000000001041466565367000214360ustar00rootroot00000000000000 linkchecker-10.5.0/tests/checker/data/base3.html.result000066400000000000000000000005751466565367000227670ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/base3.html cache key file://%(curdir)s/%(datadir)s/base3.html real url file://%(curdir)s/%(datadir)s/base3.html name %(datadir)s/base3.html valid url test.txt cache key file://%(curdir)s/%(datadir)s/base/test.txt real url file://%(curdir)s/%(datadir)s/base/test.txt baseurl file://%(curdir)s/%(datadir)s/base/ warning Content size is zero. valid linkchecker-10.5.0/tests/checker/data/base4.html000066400000000000000000000004261466565367000214460ustar00rootroot00000000000000 Blubb linkchecker-10.5.0/tests/checker/data/base4.html.result000066400000000000000000000006101466565367000227560ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/base4.html cache key file://%(curdir)s/%(datadir)s/base4.html real url file://%(curdir)s/%(datadir)s/base4.html name %(datadir)s/base4.html valid url test.txt cache key file://%(curdir)s/%(datadir)s/base/test.txt real url file://%(curdir)s/%(datadir)s/base/test.txt name Blubb baseurl file://%(curdir)s/%(datadir)s/base/ warning Content size is zero. valid linkchecker-10.5.0/tests/checker/data/base_ignorewarnings.html000066400000000000000000000001001466565367000244630ustar00rootroot00000000000000 linkchecker-10.5.0/tests/checker/data/base_ignorewarnings.html.result000066400000000000000000000006621466565367000260150ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/base_ignorewarnings.html cache key file://%(curdir)s/%(datadir)s/base_ignorewarnings.html real url file://%(curdir)s/%(datadir)s/base_ignorewarnings.html name %(datadir)s/base_ignorewarnings.html valid url test.txt cache key file://%(curdir)s/%(datadir)s/base/test.txt real url file://%(curdir)s/%(datadir)s/base/test.txt baseurl file://%(curdir)s/%(datadir)s/base/ info Content size is zero. valid linkchecker-10.5.0/tests/checker/data/base_ignorewarnings_with_warning.html000066400000000000000000000001001466565367000272430ustar00rootroot00000000000000 linkchecker-10.5.0/tests/checker/data/base_ignorewarnings_with_warning.html.result000066400000000000000000000007511466565367000305740ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/base_ignorewarnings_with_warning.html cache key file://%(curdir)s/%(datadir)s/base_ignorewarnings_with_warning.html real url file://%(curdir)s/%(datadir)s/base_ignorewarnings_with_warning.html name %(datadir)s/base_ignorewarnings_with_warning.html valid url test.txt cache key file://%(curdir)s/%(datadir)s/base/test.txt real url file://%(curdir)s/%(datadir)s/base/test.txt baseurl file://%(curdir)s/%(datadir)s/base/ warning Content size is zero. valid linkchecker-10.5.0/tests/checker/data/charsets/000077500000000000000000000000001466565367000213745ustar00rootroot00000000000000linkchecker-10.5.0/tests/checker/data/charsets/cp1250.html000066400000000000000000000003021466565367000231670ustar00rootroot00000000000000 luouk k pl belsk dy luouk k pl belsk dy linkchecker-10.5.0/tests/checker/data/charsets/cp1250.html.result000066400000000000000000000011361466565367000245120ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/charsets/cp1250.html cache key file://%(curdir)s/%(datadir)s/charsets/cp1250.html real url file://%(curdir)s/%(datadir)s/charsets/cp1250.html name %(datadir)s/charsets/cp1250.html valid url file.html cache key file://%(curdir)s/%(datadir)s/charsets/file.html real url file://%(curdir)s/%(datadir)s/charsets/file.html name Žluťoučký kúň úpěl ďábelské ódy ůůůů error url img.png cache key file://%(curdir)s/%(datadir)s/charsets/img.png real url file://%(curdir)s/%(datadir)s/charsets/img.png name Žluťoučký kúň úpěl ďábelské ódy ůůůů error linkchecker-10.5.0/tests/checker/data/charsets/iso8859-2.html000066400000000000000000000003061466565367000235500ustar00rootroot00000000000000 luouk k pl belsk dy luouk k pl belsk dy linkchecker-10.5.0/tests/checker/data/charsets/iso8859-2.html.result000066400000000000000000000011521466565367000250650ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/charsets/iso8859-2.html cache key file://%(curdir)s/%(datadir)s/charsets/iso8859-2.html real url file://%(curdir)s/%(datadir)s/charsets/iso8859-2.html name %(datadir)s/charsets/iso8859-2.html valid url file.html cache key file://%(curdir)s/%(datadir)s/charsets/file.html real url file://%(curdir)s/%(datadir)s/charsets/file.html name Žluťoučký kúň úpěl ďábelské ódy ůůůů error url img.png cache key file://%(curdir)s/%(datadir)s/charsets/img.png real url file://%(curdir)s/%(datadir)s/charsets/img.png name Žluťoučký kúň úpěl ďábelské ódy ůůůů error linkchecker-10.5.0/tests/checker/data/charsets/utf8.html000066400000000000000000000002641466565367000231520ustar00rootroot00000000000000 Žluťoučký kúň úpěl ďábelské ódy ůůůů Žluťoučký kúň úpěl ďábelské ódy ůůůů linkchecker-10.5.0/tests/checker/data/charsets/utf8.html.result000066400000000000000000000011261466565367000244650ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/charsets/utf8.html cache key file://%(curdir)s/%(datadir)s/charsets/utf8.html real url file://%(curdir)s/%(datadir)s/charsets/utf8.html name %(datadir)s/charsets/utf8.html valid url file.html cache key file://%(curdir)s/%(datadir)s/charsets/file.html real url file://%(curdir)s/%(datadir)s/charsets/file.html name Žluťoučký kúň úpěl ďábelské ódy ůůůů error url img.png cache key file://%(curdir)s/%(datadir)s/charsets/img.png real url file://%(curdir)s/%(datadir)s/charsets/img.png name Žluťoučký kúň úpěl ďábelské ódy ůůůů error linkchecker-10.5.0/tests/checker/data/cookies.txt000066400000000000000000000002371466565367000217570ustar00rootroot00000000000000Host: example.com Path: /hello Set-cookie: ID="smee" Set-cookie: spam="egg" Scheme: https Host: example.org Set-cookie: baggage="elitist"; comment="hologram" linkchecker-10.5.0/tests/checker/data/dir.result000066400000000000000000000006421466565367000216000ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/dir/ cache key file://%(curdir)s/%(datadir)s/dir/ real url file://%(curdir)s/%(datadir)s/dir/ name %(datadir)s/dir valid url %%C3%%AD%%C2%%BB%%C2%%AD%%C2%%AF%%C2%%BF.dat cache key file://%(curdir)s/%(datadir)s/dir/%%C3%%AD%%C2%%BB%%C2%%AD%%C2%%AF%%C2%%BF.dat real url file://%(curdir)s/%(datadir)s/dir/%%C3%%AD%%C2%%BB%%C2%%AD%%C2%%AF%%C2%%BF.dat name í»­¯¿.dat valid linkchecker-10.5.0/tests/checker/data/dir.zip000066400000000000000000000004261466565367000210640ustar00rootroot00000000000000PK t9dir/UT %I%IUxPK t93 dir/.datUT %I%IUx PK t9 Adir/UT%IUxPK t93 7dir/.datUT%IUxPKylinkchecker-10.5.0/tests/checker/data/empty.html000066400000000000000000000000001466565367000215720ustar00rootroot00000000000000linkchecker-10.5.0/tests/checker/data/empty.html.result000066400000000000000000000002641466565367000231230ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/empty.html cache key file://%(curdir)s/%(datadir)s/empty.html real url file://%(curdir)s/%(datadir)s/empty.html name %(datadir)s/empty.html valid linkchecker-10.5.0/tests/checker/data/favicon.ico000066400000000000000000000003061466565367000217000ustar00rootroot00000000000000( linkchecker-10.5.0/tests/checker/data/file-octet-stream.markdown000066400000000000000000000004431466565367000246510ustar00rootroot00000000000000# Test # text [link]( http://urllink.example.com) [link2](http://urllink2 .example.com) [test][id1] [URL][id2] [id1]: http://urldef1.example.com [id2]: http://urldef2.example.com "URL" ![img](http://urlimg.example.com) linkchecker-10.5.0/tests/checker/data/file-octet-stream.markdown.result000066400000000000000000000020701466565367000261640ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/file-octet-stream.markdown cache key file://%(curdir)s/%(datadir)s/file-octet-stream.markdown real url file://%(curdir)s/%(datadir)s/file-octet-stream.markdown name %(datadir)s/file-octet-stream.markdown warning The URL with content type 'application/octet-stream' is not parseable. valid url http://url.example.com cache key http://url.example.com real url http://url.example.com error url http://url2.example.com cache key http://url2.example.com real url http://url2.example.com error url http://urldef1.example.com cache key http://urldef1.example.com real url http://urldef1.example.com error url http://urldef2.example.com cache key http://urldef2.example.com real url http://urldef2.example.com error url http://urllink.example.com cache key http://urllink.example.com real url http://urllink.example.com error url http://urllink2.example.com cache key http://urllink2.example.com real url http://urllink2.example.com error url http://urlimg.example.com cache key http://urlimg.example.com real url http://urlimg.example.com error linkchecker-10.5.0/tests/checker/data/file.asc000066400000000000000000000000221466565367000211610ustar00rootroot00000000000000file:///etc/group linkchecker-10.5.0/tests/checker/data/file.asc.result000066400000000000000000000003731466565367000225070ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/file.asc cache key file://%(curdir)s/%(datadir)s/file.asc real url file://%(curdir)s/%(datadir)s/file.asc name %(datadir)s/file.asc warning The URL with content type 'application/octet-stream' is not parseable. valid linkchecker-10.5.0/tests/checker/data/file.css000066400000000000000000000001511466565367000212060ustar00rootroot00000000000000@font-face { src:url(file.html) } background-image:url(file.txt) /*background-image:url(broken.html)*/ linkchecker-10.5.0/tests/checker/data/file.css.result000066400000000000000000000006311466565367000225260ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/file.css cache key file://%(curdir)s/%(datadir)s/file.css real url file://%(curdir)s/%(datadir)s/file.css name %(datadir)s/file.css valid url file.html cache key file://%(curdir)s/%(datadir)s/file.html real url file://%(curdir)s/%(datadir)s/file.html valid url file.txt cache key file://%(curdir)s/%(datadir)s/file.txt real url file://%(curdir)s/%(datadir)s/file.txt valid linkchecker-10.5.0/tests/checker/data/file.doc000066400000000000000000000220001466565367000211600ustar00rootroot00000000000000ࡱ;  Root Entry !"$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]  FMicrosoft Word-Dokument MSWordDocWord.Document.89q [^^Standard1$*$3B*OJQJCJmHsHKHPJnHtH^JaJ_H9BA@BAbsatz-StandardschriftartHUH Internetlink B* phmHsH>*nHtH_HNN berschrift x$OJQJCJPJ^JaJ0B0 Textkrper x"/""Liste^JJ"2J Beschriftung xx $CJ6^JaJ]2B2 Verzeichnis $^J4fh&24X44PGTimes New Roman5Symbol3&ArialIArial Unicode MS5Mangal5MangalBhQMg  ' 0 0DyK yK 0http://www.example.org/Oh+'0|8 @ L X d p0@@@\bH@M 0hCaolan80 $4BBBV b lnb  HYPERLINK "http://www.example.org/"Example.org JLNdf0JjUUh". A!n"n#n$n3P(20՜.+,D՜.+,\Root Entry FCompObjjOle 1TablesData SummaryInformation( WordDocument#$DocumentSummaryInformation8\tlinkchecker-10.5.0/tests/checker/data/file.doc.result000066400000000000000000000005351466565367000225060ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/file.doc cache key file://%(curdir)s/%(datadir)s/file.doc real url file://%(curdir)s/%(datadir)s/file.doc name %(datadir)s/file.doc valid url http://www.example.org/ cache key http://www.example.org/ real url http://www.example.com/ name Example.org info Redirected to `http://www.example.com/'. valid linkchecker-10.5.0/tests/checker/data/file.html000066400000000000000000000001631466565367000213650ustar00rootroot00000000000000relative url javascript url anchor linkchecker-10.5.0/tests/checker/data/file.html.result000066400000000000000000000005011466565367000226760ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/file.html cache key file://%(curdir)s/%(datadir)s/file.html real url file://%(curdir)s/%(datadir)s/file.html name %(datadir)s/file.html valid url javascript:loadthis() cache key javascript:loadthis() real url javascript:loadthis() name javascript url info Javascript URL ignored. valid linkchecker-10.5.0/tests/checker/data/file.markdown000066400000000000000000000004431466565367000222440ustar00rootroot00000000000000# Test # text [link]( http://urllink.example.com) [link2](http://urllink2 .example.com) [test][id1] [URL][id2] [id1]: http://urldef1.example.com [id2]: http://urldef2.example.com "URL" ![img](http://urlimg.example.com) linkchecker-10.5.0/tests/checker/data/file.markdown.result000066400000000000000000000017711466565367000235660ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/file.markdown cache key file://%(curdir)s/%(datadir)s/file.markdown real url file://%(curdir)s/%(datadir)s/file.markdown name %(datadir)s/file.markdown warning The URL with content type 'text/markdown' is not parseable. valid url http://url.example.com cache key http://url.example.com real url http://url.example.com error url http://url2.example.com cache key http://url2.example.com real url http://url2.example.com error url http://urldef1.example.com cache key http://urldef1.example.com real url http://urldef1.example.com error url http://urldef2.example.com cache key http://urldef2.example.com real url http://urldef2.example.com error url http://urllink.example.com cache key http://urllink.example.com real url http://urllink.example.com error url http://urllink2.example.com cache key http://urllink2.example.com real url http://urllink2.example.com error url http://urlimg.example.com cache key http://urlimg.example.com real url http://urlimg.example.com error linkchecker-10.5.0/tests/checker/data/file.pdf000066400000000000000000000163631466565367000212030ustar00rootroot00000000000000%PDF-1.4 %äüöß 2 0 obj <> stream xU PD  v 2jc]M!69N0 > stream xU PD}B A 2jc]M!69N0 ًt91*=R:,6Q۩fif%{͹h]5|E6+_zb0MĘ]x=$P endstream endobj 6 0 obj 138 endobj 10 0 obj <> stream xX}P[Wv?>}==d'?dCML x19ɒ7zL:qIۦtfv;?=w>9K2~8 zXZax2).6;EhHltp U|p5&PKlC`ƒZƓ9MTGtkǃ߉<2yq"8_x ]G,HlY&ñ|Kf0$b؅1S5RĔ{ٸBo7Хgc8 ?>aDV^?F]>A+ܾ3(O <z>x.?qxs+K% <oehFrdsx]#dc< >y^qo9=Gc0r_!kpVGa< ; \6^DKB;@_17Hp4\j#1u޿}Wv4thq ۶nT㨮,߸V&ZLFސj*tK(oȪ [x)@pE4j$A46s`˛Jy$ѓ 3S%Rz}* ϏV3s,{73YOwߵ/SG "uj_}X&~j i^te`%IAL-IvǟU Sq=`x9fb_1PD,hW 3I 0o -X:*e=^t! fz䞮qE0-)&~ܑb1M-23VbEw*J|I]P87Y4_bʅ-6SЈl CFD*;?VbY2mH]mDNesFnp:NS3׏< ֦/WPTE?1Ò6!W+UNl9xi~Zfk5}UURhcE.8> FX-ؚRXD󳹱(UCyW2K +챛WWnUe{mI,tR{O923o-a6Yl?K nb~NM;l/mB)ߨh!Kv\Uiv=<:H m 4OYwR21"cndt`J@g(n #0ξM0d&nkztˤbv˦5}l&g}^Ee1YhM 9k!g`-Y$͹ƫEfetWcPLž588[rgUCTCLyTZ_M77ѺRʭ)LPX|y `VƺuX *%9۱*ToN8Vc7Hx2{{˶ 8շ^8p!|Yi~iXUgHQ_Y|I-4 h' ẙYKY^ 9$rv^===gog"!mRsj}Zn%Z.//נ_;U5t<'jhpMnTGxq-NsL/ E}YYso͔7 0ga1YgКY7ʸ/=7(3߾k5P@/ 8]9oAn\yZ_!>Π,:aMIvK&(֣86C:Xw7Y,CNh6}~~qx&,۳phؑSdy`ZO`'>cmSSJqyOzL8y5SS_PjNր:)S+y[Yx%6Ԙͨn;H¯ȉ>s=>G<xx sd=sJb kFCP}@QfEK֯/)2gu.͕6[]VjWYkg# '֐5j$cq(4SK̿S M5XK2e M^0Dj Ly*;?D:X-Ajxrkv_侧zjѓY /cUAgK %}eV%N:|/ZerSE?ꗰ6]Αsu%A;GxdZ(fs0=Uߞ ]K,,"=24f8UDVCiր Jց4d,#3tw@d.DɟgCw5Dc#cI|B*vC7&ŝBBd8T-v5wu/FxNƃx0YmGFã;P8.Vwk T]noH$8 Zቤˆ## *GcH"f3hcLJdXL&ÉX28rHu0Œ"DPz$b'FA{V;Ê$iQ2U=+%0o8]UbM*1w+xRYSL6p1:|ojYy8ZQwK)u +}Etϫ㸾:2P=sL֚G;*?ldK'2(qU=u+ծVQeafYe|/csV%tV 7~d6y6ocgW7*,޸rv^u:1\':}yMs,]j\#kSkI>pMF\gkfcSޘMq w;,-S˥K.q%K|yz<1wjsgm̝q2rɱ'G :s ԀGcv`:UHdgηW&'e[;dI OCv/!$B_7]D{xpG0~}4%1$DؙL! a6-%ݘԮh1*(?{o endstream endobj 11 0 obj 4467 endobj 12 0 obj <> endobj 13 0 obj <> stream x]j >˙ŠL Ld MFORab"oߣЅk֚ނSD:n h(6*T$=a95acX]{^`HwM[6RN,eס6q=/c@ˬm4^*Ҏ@j/Ajs3 2suS2es:lBnO 'W~y$ endstream endobj 14 0 obj <> endobj 15 0 obj <> endobj 16 0 obj <> endobj 1 0 obj <>/Contents 2 0 R>> endobj 4 0 obj <>/Contents 5 0 R>> endobj 9 0 obj <> endobj 7 0 obj <> >> endobj 8 0 obj <> >> endobj 17 0 obj <> endobj 18 0 obj < /Producer /CreationDate(D:20140429184612+02'00')>> endobj xref 0 19 0000000000 65535 f 0000005843 00000 n 0000000019 00000 n 0000000228 00000 n 0000006003 00000 n 0000000248 00000 n 0000000457 00000 n 0000006268 00000 n 0000006412 00000 n 0000006163 00000 n 0000000477 00000 n 0000005030 00000 n 0000005052 00000 n 0000005249 00000 n 0000005569 00000 n 0000005755 00000 n 0000005788 00000 n 0000006556 00000 n 0000006653 00000 n trailer < <3C4F50AD72F9A2B0B810994F6BEC600F> ] /DocChecksum /6EDD679AB0858B64BF6D4E674181D4C2 >> startxref 6828 %%EOF linkchecker-10.5.0/tests/checker/data/file.pdf.result000066400000000000000000000006261466565367000225130ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/file.pdf cache key file://%(curdir)s/%(datadir)s/file.pdf real url file://%(curdir)s/%(datadir)s/file.pdf name %(datadir)s/file.pdf valid url http://www.example.com/link1 cache key http://www.example.com/link1 real url http://www.example.com/link1 error url http://www.example.com/link2 cache key http://www.example.com/link2 real url http://www.example.com/link2 error linkchecker-10.5.0/tests/checker/data/file.php000066400000000000000000000002601466565367000212060ustar00rootroot00000000000000Bla PHP 1 PHP 2 linkchecker-10.5.0/tests/checker/data/file.php.result000066400000000000000000000014141466565367000225250ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/file.php cache key file://%(curdir)s/%(datadir)s/file.php real url file://%(curdir)s/%(datadir)s/file.php name %(datadir)s/file.php valid url test_ cache key file://%(curdir)s/%(datadir)s/test_%%3C?php%%20echo%%20%%24module%%20?%%3E real url file://%(curdir)s/%(datadir)s/test_%%3C?php%%20echo%%20%%24module%%20?%%3E name PHP 2 info File URL ignored. valid url test_ cache key file://%(curdir)s/%(datadir)s/test_%%3C?%%20echo%%20%%24module%%20?%%3E real url file://%(curdir)s/%(datadir)s/test_%%3C?%%20echo%%20%%24module%%20?%%3E name PHP 1 info File URL ignored. valid url anchor.html cache key file://%(curdir)s/%(datadir)s/anchor.html real url file://%(curdir)s/%(datadir)s/anchor.html name Bla valid linkchecker-10.5.0/tests/checker/data/file.txt000066400000000000000000000000221466565367000212320ustar00rootroot00000000000000file:///etc/group linkchecker-10.5.0/tests/checker/data/file.txt.result000066400000000000000000000003551466565367000225600ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/file.txt cache key file://%(curdir)s/%(datadir)s/file.txt real url file://%(curdir)s/%(datadir)s/file.txt name %(datadir)s/file.txt warning The URL with content type 'text/plain' is not parseable. valid linkchecker-10.5.0/tests/checker/data/file.wml000066400000000000000000000003771466565367000212270ustar00rootroot00000000000000

Test1

linkchecker-10.5.0/tests/checker/data/file.wml.result000066400000000000000000000006471466565367000225440ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/file.wml cache key file://%(curdir)s/%(datadir)s/file.wml real url file://%(curdir)s/%(datadir)s/file.wml name %(datadir)s/file.wml valid url file.html cache key file://%(curdir)s/%(datadir)s/file.html real url file://%(curdir)s/%(datadir)s/file.html name Test1 valid url error.gif cache key file://%(curdir)s/%(datadir)s/error.gif real url file://%(curdir)s/%(datadir)s/error.gif error linkchecker-10.5.0/tests/checker/data/file_url_quote.html000066400000000000000000000005651466565367000234720ustar00rootroot00000000000000 l1 The same address as l1 therefore not reported l2 l3 l4 linkchecker-10.5.0/tests/checker/data/file_url_quote.html.result000066400000000000000000000014661466565367000250100ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/file_url_quote.html cache key file://%(curdir)s/%(datadir)s/file_url_quote.html real url file://%(curdir)s/%(datadir)s/file_url_quote.html name %(datadir)s/file_url_quote.html valid url http://localhost:8001/?quoted=ü cache key http://localhost:8001/?quoted=%%C3%%BC real url http://localhost:8001/?quoted=%%C3%%BC name l1 error url http://localhost:8001/?quoted=%%FF cache key http://localhost:8001/?quoted=%%C3%%BF real url http://localhost:8001/?quoted=%%C3%%BF name l2 error url mailto:ölvin@users.sourceforge.net cache key mailto:ölvin@users.sourceforge.net real url mailto:%%C3%%B6lvin@users.sourceforge.net name l3 valid url mailto:%%E4lvin@users.sourceforge.net cache key mailto:älvin@users.sourceforge.net real url mailto:%%C3%%A4lvin@users.sourceforge.net name l4 valid linkchecker-10.5.0/tests/checker/data/frames.html000066400000000000000000000003031466565367000217170ustar00rootroot00000000000000 linkchecker-10.5.0/tests/checker/data/frames.html.result000066400000000000000000000006451466565367000232450ustar00rootroot00000000000000url file://%(curdir)s/%(datadir)s/frames.html cache key file://%(curdir)s/%(datadir)s/frames.html real url file://%(curdir)s/%(datadir)s/frames.html name %(datadir)s/frames.html valid url file.html cache key file://%(curdir)s/%(datadir)s/file.html real url file://%(curdir)s/%(datadir)s/file.html valid url file.txt cache key file://%(curdir)s/%(datadir)s/file.txt real url file://%(curdir)s/%(datadir)s/file.txt valid linkchecker-10.5.0/tests/checker/data/html5.html000066400000000000000000000002571466565367000215030ustar00rootroot00000000000000