pax_global_header00006660000000000000000000000064140050424360014510gustar00rootroot0000000000000052 comment=365852a4428bf9fe7e58fa0f7f2845719d531182 linkchecker-10.0.1/000077500000000000000000000000001400504243600140515ustar00rootroot00000000000000linkchecker-10.0.1/.github/000077500000000000000000000000001400504243600154115ustar00rootroot00000000000000linkchecker-10.0.1/.github/ISSUE_TEMPLATE.md000066400000000000000000000021211400504243600201120ustar00rootroot00000000000000 ## Summary ## Steps to reproduce 1. 2. 3. ## Actual result ## Expected result ## Environment * Operating system: * Linkchecker version: * Python version: * Install method: * Site URL: ## Configuration file ## Logs ## Other notes linkchecker-10.0.1/.github/workflows/000077500000000000000000000000001400504243600174465ustar00rootroot00000000000000linkchecker-10.0.1/.github/workflows/publish-pages.yml000066400000000000000000000016321400504243600227360ustar00rootroot00000000000000name: Publish LinkChecker Documentation on GitHub Pages on: push: branches: ["master"] jobs: run: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install Ubuntu packages run: sudo apt install graphviz # Ensure sphinx-autogen is installed in PATH - name: Setup Python uses: actions/setup-python@v2 - name: Install Python packages run: > pip install dnspython beautifulsoup4 pyxdg requests \ sphinx sphinx_epytext sphinx_rtd_theme - name: Build run: | python3 setup.py build make -C doc code make -C doc html - name: Publish uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./doc/html commit_message: ${{ github.event.head_commit.message }} linkchecker-10.0.1/.project000066400000000000000000000005551400504243600155250ustar00rootroot00000000000000 linkchecker org.python.pydev.PyDevBuilder org.python.pydev.pythonNature linkchecker-10.0.1/.pydevproject000066400000000000000000000006451400504243600165750ustar00rootroot00000000000000 Default python 2.7 /linkchecker-git linkchecker-10.0.1/CODE_OF_CONDUCT.rst000066400000000000000000000102421400504243600170570ustar00rootroot00000000000000Contributor 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.0.1/CONTRIBUTING.rst000066400000000000000000000134131400504243600165140ustar00rootroot00000000000000Contribution 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 Construct 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.0.1/COPYING000066400000000000000000000431031400504243600151050ustar00rootroot00000000000000 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.0.1/Dockerfile000066400000000000000000000005721400504243600160470ustar00rootroot00000000000000FROM python:3-slim # needed to allow linkchecker create plugin directory and initial configuration file in "home" dir ENV HOME /tmp RUN set -x \ && pip install --no-cache-dir https://github.com/linkchecker/linkchecker/archive/master.zip # /mnt enables linkchecker to access to access files on local machine if needed VOLUME /mnt WORKDIR /mnt ENTRYPOINT ["linkchecker"] linkchecker-10.0.1/MANIFEST.in000066400000000000000000000055631400504243600156200ustar00rootroot00000000000000include *.ini include *.md include *.rst include *.txt include COPYING include Dockerfile include MANIFEST.in include Makefile include install-rpm.sh include .project include .pydevproject recursive-include cgi-bin \ *.css \ *.de \ *.en \ *.html \ *.ico \ *.js \ README recursive-include config \ *.sql \ linkchecker-completion \ linkchecker.apache2.conf \ linkcheckerrc recursive-include doc \ *.1 \ *.5 \ *.bat \ *.css \ *.example \ *.html \ *.ico \ *.jpg \ *.md \ *.png \ *.po \ *.pot \ *.py \ *.rst \ *.sh \ *.txt \ *.yml \ Makefile \ linkcheckerrc_* recursive-include po \ *.mo \ *.po \ *.pot \ Makefile recursive-include \ scripts \ *.sh \ *.py recursive-include tests \ *.adr \ *.asc \ *.bin \ *.css \ *.doc \ *.html \ *.ico \ *.ini \ *.markdown \ *.pdf \ *.php \ *.plist \ *.py \ *.result \ *.sqlite \ *.swf \ *.txt \ *.wml \ *.xhtml \ *.xml \ *.zip \ Bookmarks recursive-include windows \ *.bat \ *.cer \ *.pfx \ *.pvk linkchecker-10.0.1/Makefile000066400000000000000000000141311400504243600155110ustar00rootroot00000000000000# This Makefile is only used by developers. PYVER:=3 PYTHON?=python$(PYVER) VERSION:=$(shell $(PYTHON) setup.py --version) PLATFORM:=$(shell $(PYTHON) -c "from __future__ import print_function; from distutils.util import get_platform; print(get_platform())") APPNAME:=$(shell $(PYTHON) setup.py --name) AUTHOR:=$(shell $(PYTHON) setup.py --author) MAINTAINER:=$(shell $(PYTHON) setup.py --maintainer) LAPPNAME:=$(shell echo $(APPNAME)|tr "[A-Z]" "[a-z]") ARCHIVE_SOURCE_EXT:=gz ARCHIVE_SOURCE:=$(APPNAME)-$(VERSION).tar.$(ARCHIVE_SOURCE_EXT) GITUSER:=linkchecker GITREPO:=$(LAPPNAME) HOMEPAGE:=$(HOME)/public_html/$(LAPPNAME)-webpage.git WEB_META:=doc/web/app.yaml DEBUILDDIR:=$(HOME)/projects/debian/official DEBORIGFILE:=$(DEBUILDDIR)/$(LAPPNAME)_$(VERSION).orig.tar.$(ARCHIVE_SOURCE_EXT) DEBPACKAGEDIR:=$(DEBUILDDIR)/$(APPNAME)-$(VERSION) FILESCHECK_URL:=http://localhost/~calvin/ SRCDIR:=${HOME}/src PY_FILES_DIRS:=linkcheck tests *.py linkchecker cgi-bin config doc/examples scripts MYPY_FILES_DIRS:=linkcheck/HtmlParser linkcheck/checker \ linkcheck/cache linkcheck/configuration linkcheck/director \ linkcheck/htmlutil linkcheck/logger linkcheck/network \ linkcheck/bookmarks linkcheck/plugins linkcheck/parser \ $(filter-out %2.py,$(wildcard linkcheck/*.py)) \ cgi-bin/lc.wsgi \ linkchecker \ *.py TESTS ?= tests # set test options, eg. to "--verbose" TESTOPTS= PAGER ?= less # options to run the pep8 utility PEP8OPTS:=--repeat --ignore=E211,E501,E225,E301,E302,E241 \ --exclude="robotparser2.py" PY2APPOPTS ?= ifeq ($(shell uname),Darwin) CHMODMINUSMINUS:= else CHMODMINUSMINUS:=-- endif # Pytest options: # - use multiple processes # - write test results in file PYTESTOPTS:=-n 4 --resultlog=testresults.txt all: @echo "Read the file doc/install.txt to see how to build and install this package." clean: -$(PYTHON) setup.py clean --all rm -f $(LAPPNAME)-out.* *-stamp* find . -name '*.py[co]' -exec rm -f {} \; find . -name '*.bak' -exec rm -f {} \; find . -depth -name '__pycache__' -exec rm -rf {} \; distclean: clean rm -rf build dist $(APPNAME).egg-info rm -f _$(APPNAME)_configdata.py MANIFEST Packages.gz # clean aborted dist builds and -out files rm -f $(LAPPNAME)-out* $(LAPPNAME).prof rm -f alexa*.log testresults.txt rm -rf $(APPNAME)-$(VERSION) rm -rf coverage dist-stamp python-build-stamp* locale: $(MAKE) -C po # to build in the current directory localbuild: locale $(PYTHON) setup.py build release: distclean releasecheck filescheck $(MAKE) dist sign register upload homepage tag changelog deb tag: git tag upstream/$(VERSION) git push --tags origin upstream/$(VERSION) upload: twine upload dist/$(ARCHIVE_SOURCE) dist/$(ARCHIVE_SOURCE).asc homepage: # update metadata @echo "version: \"$(VERSION)\"" > $(WEB_META) @echo "name: \"$(APPNAME)\"" >> $(WEB_META) @echo "lname: \"$(LAPPNAME)\"" >> $(WEB_META) @echo "maintainer: \"$(MAINTAINER)\"" >> $(WEB_META) @echo "author: \"$(AUTHOR)\"" >> $(WEB_META) git add $(WEBMETA) -git commit -m "Updated webpage meta info" # update documentation and man pages $(MAKE) -C doc man $(MAKE) -C doc/web release register: @echo "Register at Python Package Index..." $(PYTHON) setup.py register @echo "done." deb: # build a debian package [ -f $(DEBORIGFILE) ] || cp dist/$(ARCHIVE_SOURCE) $(DEBORIGFILE) sed -i -e 's/VERSION_$(LAPPNAME):=.*/VERSION_$(LAPPNAME):=$(VERSION)/' $(DEBUILDDIR)/$(LAPPNAME).mak [ -d $(DEBPACKAGEDIR) ] || (cd $(DEBUILDDIR); \ patool extract $(DEBORIGFILE); \ cd $(CURDIR); \ git checkout debian; \ cp -r debian $(DEBPACKAGEDIR); \ rm -f $(DEBPACKAGEDIR)/debian/.gitignore; \ git checkout master) $(MAKE) -C $(DEBUILDDIR) $(LAPPNAME)_clean $(LAPPNAME) chmod: -chmod -R a+rX,u+w,go-w $(CHMODMINUSMINUS) * find . -type d -exec chmod 755 {} \; dist: locale chmod rm -f dist/$(ARCHIVE_SOURCE) $(PYTHON) setup.py sdist --formats=tar gzip --best dist/$(APPNAME)-$(VERSION).tar # The check programs used here are mostly local scripts on my private system. # So for other developers there is no need to execute this target. check: check-copyright check-pofiles -v py-tabdaddy $(MYPY_FILES_DIRS) py-unittest2-compat tests/ $(MAKE) -C doc check $(MAKE) doccheck $(MAKE) pyflakes doccheck: py-check-docstrings --force $(MYPY_FILES_DIRS) filescheck: localbuild for out in text html gml sql csv xml gxml dot sitemap; do \ ./$(LAPPNAME) -o$$out -F$$out --complete -r1 -C $(FILESCHECK_URL) || exit 1; \ done update-copyright: update-copyright --holder="Bastian Kleineidam" $(PY_FILES_DIRS) releasecheck: check @if egrep -i "xx\.|xxxx|\.xx" doc/changelog.txt > /dev/null; then \ echo "Could not release: edit doc/changelog.txt release date"; false; \ fi $(PYTHON) setup.py check --restructuredtext sign: for f in $(shell find dist -name *.$(ARCHIVE_SOURCE_EXT) -o -name *.exe -o -name *.zip -o -name *.dmg); do \ [ -f $${f}.asc ] || gpg --detach-sign --armor $$f; \ done test: localbuild env LANG=en_US.utf-8 $(PYTHON) -m pytest $(PYTESTOPTS) $(TESTOPTS) $(TESTS) pyflakes: pyflakes $(PY_FILES_DIRS) 2>&1 | \ grep -v "local variable 'dummy' is assigned to but never used" | \ grep -v -E "'(setuptools|win32com|find_executable|parse_sitemap|parse_sitemapindex|parse_bookmark_data|parse_bookmark_file|wsgiref|pyftpdlib|linkchecker_rc)' imported but unused" | \ grep -v "undefined name '_'" | \ grep -v "undefined name '_n'" | cat pep8: pep8 $(PEP8OPTS) $(PY_FILES_DIRS) # Compare custom Python files with the originals diff: @for f in gzip robotparser; do \ echo "Comparing $${f}.py"; \ diff -u linkcheck/$${f}2.py $(SRCDIR)/cpython.hg/Lib/$${f}.py | $(PAGER); \ done @diff -u linkcheck/better_exchook.py $(SRCDIR)/py_better_exchook.git/better_exchook.py changelog: github-changelog $(DRYRUN) $(GITUSER) $(GITREPO) doc/changelog.txt count: @sloccount linkchecker linkcheck tests # run eclipse ide ide: eclipse -data $(CURDIR)/.. .PHONY: test changelog count pyflakes ide login upload all clean distclean .PHONY: pep8 cleandeb locale localbuild deb diff dnsdiff sign .PHONY: filescheck update-copyright releasecheck check register announce .PHONY: chmod dist release homepage linkchecker-10.0.1/README.rst000066400000000000000000000036711400504243600155470ustar00rootroot00000000000000LinkChecker ============ |Build Status|_ |License|_ .. |Build Status| image:: https://travis-ci.com/linkchecker/linkchecker.svg?branch=master .. _Build Status: https://travis-ci.com/linkchecker/linkchecker .. |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:, news:, nntp:, Telnet and local file links support - restrict link checking with regular expression filters for URLs - proxy support - username/password authorization for HTTP, FTP and Telnet - honors robots.txt exclusion protocol - Cookie support - HTML5 support - a command line and web interface - various check plugins available, eg. HTML syntax and antivirus checks. Installation ------------- See `doc/install.txt`_ in the source code archive for general information. Except the given information there, please take note of the following: .. _doc/install.txt: doc/install.txt Python 3.6 or later is needed. The version in the pip repository may be old. Instead, you can use pip to install the latest code from git: ``pip3 install git+https://github.com/linkchecker/linkchecker.git``. Usage ------ Execute ``linkchecker https://www.example.com``. For other options see ``linkchecker --help``. Docker usage ------------- *The Docker images are out-of-date, pip installation is the only currently recommended method.* If you do not want to install any additional libraries/dependencies you can use the Docker image. Example for external web site check:: docker run --rm -it -u $(id -u):$(id -g) linkchecker/linkchecker --verbose https://www.example.com Local HTML file check:: docker run --rm -it -u $(id -u):$(id -g) -v "$PWD":/mnt linkchecker/linkchecker --verbose index.html linkchecker-10.0.1/cgi-bin/000077500000000000000000000000001400504243600153615ustar00rootroot00000000000000linkchecker-10.0.1/cgi-bin/README000066400000000000000000000002631400504243600162420ustar00rootroot00000000000000For 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.0.1/cgi-bin/lc.wsgi000066400000000000000000000014471400504243600166600ustar00rootroot00000000000000#!/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.0.1/cgi-bin/lconline/000077500000000000000000000000001400504243600171645ustar00rootroot00000000000000linkchecker-10.0.1/cgi-bin/lconline/check.js000066400000000000000000000011221400504243600205730ustar00rootroot00000000000000// 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.0.1/cgi-bin/lconline/favicon.ico000066400000000000000000000070661400504243600213160ustar00rootroot00000000000000h& ( @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.0.1/cgi-bin/lconline/index.html000066400000000000000000000007721400504243600211670ustar00rootroot00000000000000 LinkChecker Online Please use a frame capable browser. linkchecker-10.0.1/cgi-bin/lconline/lc.css000066400000000000000000000003601400504243600202730ustar00rootroot00000000000000h2 { 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.0.1/cgi-bin/lconline/lc_cgi.html.de000066400000000000000000000035171400504243600216670ustar00rootroot00000000000000 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.0.1/cgi-bin/lconline/lc_cgi.html.en000066400000000000000000000032331400504243600216740ustar00rootroot00000000000000 LinkChecker Online

LinkChecker Online

(powered by LinkChecker)
Url:
Options: Recursion Level: Check anchors in HTML:
Log only warnings and errors: Output language:
linkchecker-10.0.1/cgi-bin/lconline/leer.html.de000066400000000000000000000006051400504243600213710ustar00rootroot00000000000000 Leer
Keine Links geprüft!
linkchecker-10.0.1/cgi-bin/lconline/leer.html.en000066400000000000000000000006101400504243600213770ustar00rootroot00000000000000 Empty
No links checked, dude!
linkchecker-10.0.1/config/000077500000000000000000000000001400504243600153165ustar00rootroot00000000000000linkchecker-10.0.1/config/create.sql000066400000000000000000000012011400504243600172740ustar00rootroot00000000000000-- 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.0.1/config/linkchecker-completion000066400000000000000000000007621400504243600216770ustar00rootroot00000000000000# 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.0.1/config/linkchecker.apache2.conf000066400000000000000000000020611400504243600217500ustar00rootroot00000000000000 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.0.1/config/linkcheckerrc000066400000000000000000000206571400504243600200620ustar00rootroot00000000000000# 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 #debug=all # print status output #status=1 # change the logging type #log=xml # turn on/off --verbose #verbose=1 # turn on/off --warnings #warnings=0 # turn on/off --quiet #quiet=1 # additional file output #fileoutput = text, html, gml, sql ##################### 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 # 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=white #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 # default encoding is iso-8859-15 #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 #encoding=iso-8859-15 # CSV logger [csv] #filename=linkchecker-out.csv #separator=, #quotechar=" #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=~/.linkchecker/failures # custom xml logger [xml] #encoding=iso-8859-1 # GraphXML logger [gxml] #encoding=iso-8859-1 # Sitemap logger [sitemap] #priority=0.7 #frequency=weekly ##################### 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 # Basic NNTP server. Overrides NNTP_SERVER environment variable. #nntpserver= # parse a cookiefile for initial cookie data #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. #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. #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. #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. #allowedschemes=http,https ##################### 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 in invalid URLs. #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=1 ##################### 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. #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. #prefixes=Server,X- # Add country info to URLs #[LocationInfo] # Run W3C syntax checks #[CssSyntaxCheck] #[HtmlSyntaxCheck] # Search for regular expression in page contents #[RegexCheck] #warningregex=Oracle Error # Search for viruses in page contents #[VirusCheck] #clamavconf=/etc/clamav/clam.conf # Check that SSL certificates are at least the given number of days valid. #[SslCertificateCheck] #sslcertwarndays=14 # 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=.*\.(blog|markdown|md(own)?|mkdn?)$ linkchecker-10.0.1/dev-requirements.txt000066400000000000000000000001261400504243600201100ustar00rootroot00000000000000# for testing: miniboa parameterized pdfminer pyftpdlib pyopenssl pytest pytest-xdist linkchecker-10.0.1/doc/000077500000000000000000000000001400504243600146165ustar00rootroot00000000000000linkchecker-10.0.1/doc/Makefile000066400000000000000000000012201400504243600162510ustar00rootroot00000000000000MANFILES:=linkchecker.1 linkcheckerrc.5 LOCALES:=en de all: html man code: clean PYTHONPATH=.. sphinx-autogen src/code/index.rst html: 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 makefiles 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.0.1/doc/changelog.txt000066400000000000000000003362151400504243600173200ustar00rootroot0000000000000010.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 and whatsapp 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.0.1/doc/development.md000066400000000000000000000044651400504243600174730ustar00rootroot00000000000000Developing LinkChecker ====================== The following steps describe how to compile LinkChecker from source on various platforms. This is a technical document, if you are looking for ways to participate in the community, you should rather look into [contributing](contributing). Requirements ------------ On Mac OS X systems, using MacPorts, Fink or homebrew for software installation is recommended. - Install Python >= 2.7.2 from http://www.python.org/ - *On Windows only*, install the Windows SDK http://msdn.microsoft.com/de-de/windows/bb980924 - *On Windows only*, download and install the Microsoft Visual C++ 2008 runtime from http://www.microsoft.com/downloads/details.aspx?FamilyID=9b2da534-3e03-4391-8a4d-074b9f2bc1bf&displaylang=en - *Optional, used for Virus checking:* ClamAv for Unix from http://www.clamav.net/lang/en/download/ or for Windows from http://www.sosdg.org/clamav-win32/ - *Optional, for displaying country codes:* Pygeoip from http://code.google.com/p/pygeoip/ Setup for Unix/Linux -------------------- Execute ``make localbuild`` to compile a local version and execute ``./linkchecker``. Execute ``make test`` to run the unittest suite. Execute ``make dist`` to build a distributable source package. Setup for Mac OS X ------------------ Execute ``make localbuild`` to compile a local version and execute ``./linkchecker``. Execute ``make test`` to run the unittest suite. Execute ``make app`` to build a distributable source package. Setup for Windows ----------------- Execute ``windows\build.bat`` to build a local version. Execute ``windows\test.bat`` to run the unittest suite. Execute ``windows\dist.bat`` to build a binary installer. Release process --------------- 1. check whether updated translations need committing (`make locale; make -C doc locale; make -C doc man`) 2. bump AppVersion in `setup.py`, edit `changelog.txt`, and if applicable the copyright date in `linkcheck/configuration/__init__.py` 3. confirm tests have passed 4. submit a pull request 5. create a new git clone 6. build Python distribution files (`setup.py sdist bdist_wheel`) 7. check distribution files (`twine check dist/*`) and upload to PyPI (`twine upload dist/*`) 8. create release (vX.Y.Z) on GitHub (GitHub creates the .tar.gz and .zip archives) 9. increment AppVersion to vX.Y.Z+1.dev0 linkchecker-10.0.1/doc/documentation.md000066400000000000000000000030261400504243600200120ustar00rootroot00000000000000LinkChecker 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 Configuration ------------- Before building either man pages or HTML, generate ``_LinkChecker_configdata.py`` containing copyright, author and version with: ``linkchecker $ ./setup.py build`` 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 ---- ``doc/src/code/index.rst`` gives an overview of the LinkChecker code, optionally a navigable copy of the LinkChecker source can be created with: ``linkchecker/doc $ make code`` 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.0.1/doc/dot-travis-osx.yml000066400000000000000000000007131400504243600202450ustar00rootroot00000000000000language: - objective-c - python python: - "2.7" # whitelist of git branches to build branches: only: - travis # install required programs before_install: - brew update - brew install python - brew install gettext - brew link --force gettext # command to install dependencies install: - pip install -r requirements.txt --use-mirrors # command to run tests script: make app # do not send emails of broken builds notifications: email: false linkchecker-10.0.1/doc/examples/000077500000000000000000000000001400504243600164345ustar00rootroot00000000000000linkchecker-10.0.1/doc/examples/check_failures.sh000077500000000000000000000021521400504243600217420ustar00rootroot00000000000000#!/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="$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.0.1/doc/examples/check_for_x_errors.sh000077500000000000000000000020021400504243600226330ustar00rootroot00000000000000#!/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.0.1/doc/examples/check_urls.sh000077500000000000000000000030601400504243600211140ustar00rootroot00000000000000#!/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 $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$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.0.1/doc/examples/filter_xml_output.py000066400000000000000000000030651400504243600225770ustar00rootroot00000000000000#!/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.0.1/doc/examples/linkcheckerrc_loginurl000066400000000000000000000005211400504243600230770ustar00rootroot00000000000000# 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.0.1/doc/examples/windows.bat000066400000000000000000000004051400504243600206150ustar00rootroot00000000000000@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.0.1/doc/i18n/000077500000000000000000000000001400504243600153755ustar00rootroot00000000000000linkchecker-10.0.1/doc/i18n/gettext/000077500000000000000000000000001400504243600170615ustar00rootroot00000000000000linkchecker-10.0.1/doc/i18n/gettext/index.pot000066400000000000000000000066641400504243600207300ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) 2000-2016 Bastian Kleineidam, 2010-2020 LinkChecker Authors # This file is distributed under the same license as the LinkChecker package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: LinkChecker 2020-09-25\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-09-25 19:12+0100\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.6 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 "See the :doc:`installation document ` for more information." msgstr "" #: ../../src/index.rst:27 msgid "Basic usage" msgstr "" #: ../../src/index.rst:28 msgid "To check a URL like *http://www.example.org/myhomepage/* it is enough to execute:" msgstr "" #: ../../src/index.rst:35 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:41 msgid "Features" msgstr "" #: ../../src/index.rst:43 msgid "recursive and multithreaded checking and site crawling" msgstr "" #: ../../src/index.rst:44 msgid "output in colored or normal text, HTML, SQL, CSV, XML or a sitemap graph in different formats" msgstr "" #: ../../src/index.rst:46 msgid "HTTP/1.1, HTTPS, FTP, mailto:, news:, nntp:, Telnet and local file links support" msgstr "" #: ../../src/index.rst:48 msgid "restriction of link checking with regular expression filters for URLs" msgstr "" #: ../../src/index.rst:49 msgid "proxy support" msgstr "" #: ../../src/index.rst:50 msgid "username/password authorization for HTTP and FTP and Telnet" msgstr "" #: ../../src/index.rst:51 msgid "honors robots.txt exclusion protocol" msgstr "" #: ../../src/index.rst:52 msgid "Cookie support" msgstr "" #: ../../src/index.rst:53 msgid "HTML5 support" msgstr "" #: ../../src/index.rst:54 msgid ":ref:`Plugin support ` allowing custom page checks. Currently available are HTML and CSS syntax checks, Antivirus checks, and more." msgstr "" #: ../../src/index.rst:56 msgid "Different interfaces: command line and web interface" msgstr "" #: ../../src/index.rst:57 msgid "... and a lot more check options documented in the :doc:`man/linkchecker` manual page." msgstr "" #: ../../src/index.rst:61 msgid "Screenshots" msgstr "" #: ../../src/index.rst:71 msgid "Commandline interface" msgstr "" #: ../../src/index.rst:72 msgid "WSGI web interface" msgstr "" #: ../../src/index.rst:75 msgid "Test suite status" msgstr "" #: ../../src/index.rst:76 msgid "Linkchecker has extensive unit tests to ensure code quality. `Travis CI `_ is used for continuous build and test integration." msgstr "" linkchecker-10.0.1/doc/i18n/gettext/man.pot000066400000000000000000001520251400504243600203650ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) 2000-2016 Bastian Kleineidam, 2010-2020 LinkChecker Authors # This file is distributed under the same license as the LinkChecker package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: LinkChecker 2020-09-25\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-09-25 19:12+0100\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:, 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 "" #: ../../src/man/linkchecker.rst:32 msgid "EXAMPLES" msgstr "" #: ../../src/man/linkchecker.rst:34 msgid "The most common use checks the given domain recursively:" msgstr "" #: ../../src/man/linkchecker.rst:40 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:43 msgid "Don't check URLs with **/secret** in its name. All other links are checked as usual:" msgstr "" #: ../../src/man/linkchecker.rst:50 msgid "Checking a local HTML file on Unix:" msgstr "" #: ../../src/man/linkchecker.rst:56 msgid "Checking a local HTML file on Windows:" msgstr "" #: ../../src/man/linkchecker.rst:62 msgid "You can skip the **http://** url part if the domain starts with **www.**:" msgstr "" #: ../../src/man/linkchecker.rst:69 msgid "You can skip the **ftp://** url part if the domain starts with **ftp.**:" msgstr "" #: ../../src/man/linkchecker.rst:75 msgid "Generate a sitemap graph and convert it with the graphviz dot utility:" msgstr "" #: ../../src/man/linkchecker.rst:82 msgid "OPTIONS" msgstr "" #: ../../src/man/linkchecker.rst:85 msgid "General options" msgstr "" #: ../../src/man/linkchecker.rst:89 msgid "Use FILENAME as configuration file. By default LinkChecker uses ~/.linkchecker/linkcheckerrc." msgstr "" #: ../../src/man/linkchecker.rst:94 msgid "Help me! Print usage information for this program." msgstr "" #: ../../src/man/linkchecker.rst:98 msgid "Read list of white-space separated URLs to check from stdin." msgstr "" #: ../../src/man/linkchecker.rst:102 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:107 msgid "Print version and exit." msgstr "" #: ../../src/man/linkchecker.rst:111 msgid "Print available check plugins and exit." msgstr "" #: ../../src/man/linkchecker.rst:114 msgid "Output options" msgstr "" #: ../../src/man/linkchecker.rst:118 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 "" #: ../../src/man/linkchecker.rst:127 msgid "Output to a file linkchecker-out.TYPE, $HOME/.linkchecker/failures for failures 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 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:143 msgid "Do not print check status messages." msgstr "" #: ../../src/man/linkchecker.rst:147 msgid "Don't log warnings. Default is to log warnings." msgstr "" #: ../../src/man/linkchecker.rst:151 msgid "Specify 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:161 msgid "Quiet operation, an alias for :option:`-o` *none*. This is only useful with :option:`-F`." msgstr "" #: ../../src/man/linkchecker.rst:166 msgid "Log all checked URLs. Default is to log only errors and warnings." msgstr "" #: ../../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 "" #: ../../src/man/linkchecker.rst:180 msgid "Checking options" msgstr "" #: ../../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 only be syntax checked. This option can be given multiple times. See section `REGULAR EXPRESSIONS`_ for more info." msgstr "" #: ../../src/man/linkchecker.rst:199 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 "" #: ../../src/man/linkchecker.rst:205 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:212 msgid "Check URLs regardless of any robots.txt files." msgstr "" #: ../../src/man/linkchecker.rst:216 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:222 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:227 msgid "Set the timeout for connection attempts in seconds. The default timeout is 60 seconds." msgstr "" #: ../../src/man/linkchecker.rst:232 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:238 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:243 msgid "CONFIGURATION FILES" msgstr "" #: ../../src/man/linkchecker.rst:245 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:250 msgid "OUTPUT TYPES" msgstr "" #: ../../src/man/linkchecker.rst:252 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:256 msgid "**text**" msgstr "" #: ../../src/man/linkchecker.rst:257 msgid "Standard text logger, logging URLs in keyword: argument fashion." msgstr "" #: ../../src/man/linkchecker.rst:260 msgid "**html**" msgstr "" #: ../../src/man/linkchecker.rst:259 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:262 msgid "**csv**" msgstr "" #: ../../src/man/linkchecker.rst:263 msgid "Log check result in CSV format with one URL per line." msgstr "" #: ../../src/man/linkchecker.rst:265 msgid "**gml**" msgstr "" #: ../../src/man/linkchecker.rst:265 msgid "Log parent-child relations between linked URLs as a GML sitemap graph." msgstr "" #: ../../src/man/linkchecker.rst:268 msgid "**dot**" msgstr "" #: ../../src/man/linkchecker.rst:268 msgid "Log parent-child relations between linked URLs as a DOT sitemap graph." msgstr "" #: ../../src/man/linkchecker.rst:270 msgid "**gxml**" msgstr "" #: ../../src/man/linkchecker.rst:271 msgid "Log check result as a GraphXML sitemap graph." msgstr "" #: ../../src/man/linkchecker.rst:272 msgid "**xml**" msgstr "" #: ../../src/man/linkchecker.rst:273 msgid "Log check result as machine-readable XML." msgstr "" #: ../../src/man/linkchecker.rst:275 msgid "**sitemap**" msgstr "" #: ../../src/man/linkchecker.rst:275 msgid "Log check result as an XML sitemap whose protocol is documented at https://www.sitemaps.org/protocol.html." msgstr "" #: ../../src/man/linkchecker.rst:278 msgid "**sql**" msgstr "" #: ../../src/man/linkchecker.rst:278 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:282 msgid "**failures**" msgstr "" #: ../../src/man/linkchecker.rst:281 msgid "Suitable for cron jobs. Logs the check result into a file **~/.linkchecker/failures** which only contains entries with invalid URLs and the number of times they have failed." msgstr "" #: ../../src/man/linkchecker.rst:285 msgid "**none**" msgstr "" #: ../../src/man/linkchecker.rst:285 msgid "Logs nothing. Suitable for debugging or checking the exit code." msgstr "" #: ../../src/man/linkchecker.rst:288 msgid "REGULAR EXPRESSIONS" msgstr "" #: ../../src/man/linkchecker.rst:290 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:296 msgid "COOKIE FILES" msgstr "" #: ../../src/man/linkchecker.rst:298 msgid "A cookie file contains standard HTTP header (RFC 2616) data with the following possible names:" msgstr "" #: ../../src/man/linkchecker.rst:301 msgid "**Host** (required)" msgstr "" #: ../../src/man/linkchecker.rst:302 msgid "Sets the domain the cookies are valid for." msgstr "" #: ../../src/man/linkchecker.rst:303 msgid "**Path** (optional)" msgstr "" #: ../../src/man/linkchecker.rst:304 msgid "Gives the path the cookies are value for; default path is **/**." msgstr "" #: ../../src/man/linkchecker.rst:306 msgid "**Set-cookie** (required)" msgstr "" #: ../../src/man/linkchecker.rst:306 msgid "Set cookie name/value. Can be given more than once." msgstr "" #: ../../src/man/linkchecker.rst:308 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:326 msgid "PROXY SUPPORT" msgstr "" #: ../../src/man/linkchecker.rst:328 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:338 msgid "Setting a HTTP proxy on Unix for example looks like this:" msgstr "" #: ../../src/man/linkchecker.rst:344 msgid "Proxy authentication is also supported:" msgstr "" #: ../../src/man/linkchecker.rst:350 msgid "Setting a proxy on the Windows command prompt:" msgstr "" #: ../../src/man/linkchecker.rst:357 msgid "PERFORMED CHECKS" msgstr "" #: ../../src/man/linkchecker.rst:359 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:370 msgid "HTTP links (**http:**, **https:**)" msgstr "" #: ../../src/man/linkchecker.rst:365 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:370 msgid "HTML page contents are checked for recursion." msgstr "" #: ../../src/man/linkchecker.rst:377 msgid "Local files (**file:**)" msgstr "" #: ../../src/man/linkchecker.rst:373 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:377 msgid "HTML or other parseable file contents are checked for recursion." msgstr "" #: ../../src/man/linkchecker.rst:392 msgid "Mail links (**mailto:**)" msgstr "" #: ../../src/man/linkchecker.rst:380 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:384 msgid "Check the address syntax, both the parts before and after the @ sign." msgstr "" #: ../../src/man/linkchecker.rst:386 msgid "Look up the MX DNS records. If we found no MX record, print an error." msgstr "" #: ../../src/man/linkchecker.rst:388 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:391 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:401 msgid "FTP links (**ftp:**)" msgstr "" #: ../../src/man/linkchecker.rst:395 msgid "For FTP links we do:" msgstr "" #: ../../src/man/linkchecker.rst:397 msgid "connect to the specified host" msgstr "" #: ../../src/man/linkchecker.rst:398 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:400 msgid "try to change to the given directory" msgstr "" #: ../../src/man/linkchecker.rst:401 msgid "list the file with the NLST command" msgstr "" #: ../../src/man/linkchecker.rst:405 msgid "Telnet links (**telnet:**)" msgstr "" #: ../../src/man/linkchecker.rst:404 msgid "We try to connect and if user/password are given, login to the given telnet server." msgstr "" #: ../../src/man/linkchecker.rst:409 msgid "NNTP links (**news:**, **snews:**, **nntp**)" msgstr "" #: ../../src/man/linkchecker.rst:408 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:418 msgid "Unsupported links (**javascript:**, etc.)" msgstr "" #: ../../src/man/linkchecker.rst:412 msgid "An unsupported link will only print a warning. No further checking will be made." msgstr "" #: ../../src/man/linkchecker.rst:415 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:421 #: ../../src/man/linkcheckerrc.rst:422 msgid "PLUGINS" msgstr "" #: ../../src/man/linkchecker.rst:423 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:433 msgid "RECURSION" msgstr "" #: ../../src/man/linkchecker.rst:435 msgid "Before descending recursively into a URL, it has to fulfill several conditions. They are checked in this order:" msgstr "" #: ../../src/man/linkchecker.rst:438 msgid "A URL must be valid." msgstr "" #: ../../src/man/linkchecker.rst:439 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:443 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:445 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:447 msgid "It must not match the ignored URL list. This is controlled with the :option:`--ignore-url` option." msgstr "" #: ../../src/man/linkchecker.rst:449 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:453 msgid "Note that the directory recursion reads all files in that directory, not just a subset like **index.htm**." msgstr "" #: ../../src/man/linkchecker.rst:457 msgid "NOTES" msgstr "" #: ../../src/man/linkchecker.rst:459 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:467 msgid "Javascript links are not supported." msgstr "" #: ../../src/man/linkchecker.rst:469 msgid "If your platform does not support threading, LinkChecker disables it automatically." msgstr "" #: ../../src/man/linkchecker.rst:472 msgid "You can supply multiple user/password pairs in a configuration file." msgstr "" #: ../../src/man/linkchecker.rst:474 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 "" #: ../../src/man/linkchecker.rst:478 msgid "ENVIRONMENT" msgstr "" #: ../../src/man/linkchecker.rst:482 msgid "specifies default NNTP server" msgstr "" #: ../../src/man/linkchecker.rst:486 msgid "specifies default HTTP proxy server" msgstr "" #: ../../src/man/linkchecker.rst:490 msgid "specifies default FTP proxy server" msgstr "" #: ../../src/man/linkchecker.rst:494 msgid "comma-separated list of domains to not contact over a proxy server" msgstr "" #: ../../src/man/linkchecker.rst:498 msgid "specify output language" msgstr "" #: ../../src/man/linkchecker.rst:501 msgid "RETURN VALUE" msgstr "" #: ../../src/man/linkchecker.rst:503 msgid "The return value is 2 when" msgstr "" #: ../../src/man/linkchecker.rst:505 msgid "a program error occurred." msgstr "" #: ../../src/man/linkchecker.rst:507 msgid "The return value is 1 when" msgstr "" #: ../../src/man/linkchecker.rst:509 msgid "invalid links were found or" msgstr "" #: ../../src/man/linkchecker.rst:510 msgid "link warnings were found and warnings are enabled" msgstr "" #: ../../src/man/linkchecker.rst:512 msgid "Else the return value is zero." msgstr "" #: ../../src/man/linkchecker.rst:515 msgid "LIMITATIONS" msgstr "" #: ../../src/man/linkchecker.rst:517 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:522 msgid "FILES" msgstr "" #: ../../src/man/linkchecker.rst:524 msgid "**~/.linkchecker/linkcheckerrc** - default configuration file" msgstr "" #: ../../src/man/linkchecker.rst:526 msgid "**~/.linkchecker/failures** - default failures logger output filename" msgstr "" #: ../../src/man/linkchecker.rst:528 msgid "**linkchecker-out.**\\ *TYPE* - default logger file output name" msgstr "" #: ../../src/man/linkchecker.rst:531 #: ../../src/man/linkcheckerrc.rst:550 msgid "SEE ALSO" msgstr "" #: ../../src/man/linkchecker.rst:533 msgid ":manpage:`linkcheckerrc(5)`" msgstr "" #: ../../src/man/linkchecker.rst:535 msgid "https://docs.python.org/library/codecs.html#standard-encodings - valid output encodings" msgstr "" #: ../../src/man/linkchecker.rst:538 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:26 msgid "**debugmemory=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:25 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:33 msgid "**localwebroot=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:29 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 "**nntpserver=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:36 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 "" #: ../../src/man/linkcheckerrc.rst:42 msgid "**recursionlevel=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:41 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:46 msgid "**threads=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:45 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:50 msgid "**timeout=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:49 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:55 msgid "**aborttimeout=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:53 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:60 msgid "**useragent=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:58 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:66 msgid "**sslverify=**\\ [**0**\\ \\|\\ **1**\\ \\|\\ *filename*]" msgstr "" #: ../../src/man/linkcheckerrc.rst:63 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:72 msgid "**maxrunseconds=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:69 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:78 msgid "**maxfilesizedownload=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:75 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:82 msgid "**maxfilesizeparse=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:81 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:87 msgid "**maxnumurls=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:85 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:90 msgid "Limit the maximum number of requests per second to one host. 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:100 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:103 msgid "filtering" msgstr "" #: ../../src/man/linkcheckerrc.rst:106 msgid "**ignore=**\\ *REGEX* (`MULTILINE`_)" msgstr "" #: ../../src/man/linkcheckerrc.rst:106 msgid "Only check syntax of URLs matching the given regular expressions. Command line option: :option:`--ignore-url`" msgstr "" #: ../../src/man/linkcheckerrc.rst:110 msgid "**ignorewarnings=**\\ *NAME*\\ [**,**\\ *NAME*...]" msgstr "" #: ../../src/man/linkcheckerrc.rst:109 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:114 msgid "**internlinks=**\\ *REGEX*" msgstr "" #: ../../src/man/linkcheckerrc.rst:113 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:118 msgid "**nofollow=**\\ *REGEX* (`MULTILINE`_)" msgstr "" #: ../../src/man/linkcheckerrc.rst:117 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:122 msgid "**checkextern=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:121 msgid "Check external links. Default is to check internal links only. Command line option: :option:`--check-extern`" msgstr "" #: ../../src/man/linkcheckerrc.rst:125 msgid "authentication" msgstr "" #: ../../src/man/linkcheckerrc.rst:138 msgid "**entry=**\\ *REGEX* *USER* [*PASS*] (`MULTILINE`_)" msgstr "" #: ../../src/man/linkcheckerrc.rst:128 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:145 msgid "**loginurl=**\\ *URL*" msgstr "" #: ../../src/man/linkcheckerrc.rst:141 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:147 msgid "**loginuserfield=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:148 msgid "The name attribute of the username input element. Default: **login**." msgstr "" #: ../../src/man/linkcheckerrc.rst:149 msgid "**loginpasswordfield=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:150 msgid "The name attribute of the password input element. Default: **password**." msgstr "" #: ../../src/man/linkcheckerrc.rst:155 msgid "**loginextrafields=**\\ *NAME*\\ **:**\\ *VALUE* (`MULTILINE`_)" msgstr "" #: ../../src/man/linkcheckerrc.rst:152 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:158 msgid "output" msgstr "" #: ../../src/man/linkcheckerrc.rst:164 msgid "**debug=**\\ *STRING*\\ [**,**\\ *STRING*...]" msgstr "" #: ../../src/man/linkcheckerrc.rst:161 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 "" #: ../../src/man/linkcheckerrc.rst:172 msgid "**fileoutput=**\\ *TYPE*\\ [**,**\\ *TYPE*...]" msgstr "" #: ../../src/man/linkcheckerrc.rst:167 msgid "Output to a file **linkchecker-out.**\\ *TYPE*, or **$HOME/.linkchecker/failures** for **failures** output. 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:180 msgid "**log=**\\ *TYPE*\\ [**/**\\ *ENCODING*]" msgstr "" #: ../../src/man/linkcheckerrc.rst:175 msgid "Specify 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:184 msgid "**quiet=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:183 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:187 msgid "**status=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:187 msgid "Control printing check status messages. Default is 1. Command line option: :option:`--no-status`" msgstr "" #: ../../src/man/linkcheckerrc.rst:191 msgid "**verbose=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:190 msgid "If set log all checked URLs once. Default is to log only errors and warnings. Command line option: :option:`--verbose`" msgstr "" #: ../../src/man/linkcheckerrc.rst:195 msgid "**warnings=**\\ [**0**\\ \\|\\ **1**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:194 msgid "If set log warnings. Default is to log warnings. Command line option: :option:`--no-warnings`" msgstr "" #: ../../src/man/linkcheckerrc.rst:198 msgid "text" msgstr "" #: ../../src/man/linkcheckerrc.rst:202 #: ../../src/man/linkcheckerrc.rst:246 #: ../../src/man/linkcheckerrc.rst:256 #: ../../src/man/linkcheckerrc.rst:266 #: ../../src/man/linkcheckerrc.rst:280 #: ../../src/man/linkcheckerrc.rst:294 #: ../../src/man/linkcheckerrc.rst:318 #: ../../src/man/linkcheckerrc.rst:326 #: ../../src/man/linkcheckerrc.rst:336 #: ../../src/man/linkcheckerrc.rst:346 msgid "**filename=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:201 msgid "Specify output filename for text logging. Default filename is **linkchecker-out.txt**. Command line option: :option:`--file-output`" msgstr "" #: ../../src/man/linkcheckerrc.rst:206 #: ../../src/man/linkcheckerrc.rst:248 #: ../../src/man/linkcheckerrc.rst:258 #: ../../src/man/linkcheckerrc.rst:268 #: ../../src/man/linkcheckerrc.rst:282 #: ../../src/man/linkcheckerrc.rst:296 #: ../../src/man/linkcheckerrc.rst:328 #: ../../src/man/linkcheckerrc.rst:338 #: ../../src/man/linkcheckerrc.rst:348 msgid "**parts=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:205 msgid "Comma-separated list of parts that have to be logged. See `LOGGER PARTS`_ below. Command line option: none" msgstr "" #: ../../src/man/linkcheckerrc.rst:210 #: ../../src/man/linkcheckerrc.rst:251 #: ../../src/man/linkcheckerrc.rst:261 #: ../../src/man/linkcheckerrc.rst:270 #: ../../src/man/linkcheckerrc.rst:284 #: ../../src/man/linkcheckerrc.rst:298 #: ../../src/man/linkcheckerrc.rst:321 #: ../../src/man/linkcheckerrc.rst:331 #: ../../src/man/linkcheckerrc.rst:341 #: ../../src/man/linkcheckerrc.rst:350 msgid "**encoding=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:209 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:218 msgid "*color\\**" msgstr "" #: ../../src/man/linkcheckerrc.rst:213 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:220 msgid "**colorparent=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:221 msgid "Set parent color. Default is **white**." msgstr "" #: ../../src/man/linkcheckerrc.rst:222 msgid "**colorurl=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:223 msgid "Set URL color. Default is **default**." msgstr "" #: ../../src/man/linkcheckerrc.rst:224 msgid "**colorname=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:225 msgid "Set name color. Default is **default**." msgstr "" #: ../../src/man/linkcheckerrc.rst:226 msgid "**colorreal=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:227 msgid "Set real URL color. Default is **cyan**." msgstr "" #: ../../src/man/linkcheckerrc.rst:228 msgid "**colorbase=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:229 msgid "Set base URL color. Default is **purple**." msgstr "" #: ../../src/man/linkcheckerrc.rst:230 msgid "**colorvalid=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:231 msgid "Set valid color. Default is **bold;green**." msgstr "" #: ../../src/man/linkcheckerrc.rst:232 msgid "**colorinvalid=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:233 msgid "Set invalid color. Default is **bold;red**." msgstr "" #: ../../src/man/linkcheckerrc.rst:234 msgid "**colorinfo=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:235 msgid "Set info color. Default is **default**." msgstr "" #: ../../src/man/linkcheckerrc.rst:236 msgid "**colorwarning=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:237 msgid "Set warning color. Default is **bold;yellow**." msgstr "" #: ../../src/man/linkcheckerrc.rst:238 msgid "**colordltime=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:239 msgid "Set download time color. Default is **default**." msgstr "" #: ../../src/man/linkcheckerrc.rst:241 msgid "**colorreset=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:241 msgid "Set reset color. Default is **default**." msgstr "" #: ../../src/man/linkcheckerrc.rst:244 msgid "gml" msgstr "" #: ../../src/man/linkcheckerrc.rst:247 #: ../../src/man/linkcheckerrc.rst:249 #: ../../src/man/linkcheckerrc.rst:251 #: ../../src/man/linkcheckerrc.rst:257 #: ../../src/man/linkcheckerrc.rst:259 #: ../../src/man/linkcheckerrc.rst:261 #: ../../src/man/linkcheckerrc.rst:267 #: ../../src/man/linkcheckerrc.rst:269 #: ../../src/man/linkcheckerrc.rst:271 #: ../../src/man/linkcheckerrc.rst:281 #: ../../src/man/linkcheckerrc.rst:283 #: ../../src/man/linkcheckerrc.rst:285 #: ../../src/man/linkcheckerrc.rst:295 #: ../../src/man/linkcheckerrc.rst:297 #: ../../src/man/linkcheckerrc.rst:299 #: ../../src/man/linkcheckerrc.rst:319 #: ../../src/man/linkcheckerrc.rst:321 #: ../../src/man/linkcheckerrc.rst:327 #: ../../src/man/linkcheckerrc.rst:329 #: ../../src/man/linkcheckerrc.rst:331 #: ../../src/man/linkcheckerrc.rst:337 #: ../../src/man/linkcheckerrc.rst:339 #: ../../src/man/linkcheckerrc.rst:341 #: ../../src/man/linkcheckerrc.rst:347 #: ../../src/man/linkcheckerrc.rst:349 #: ../../src/man/linkcheckerrc.rst:351 msgid "See :ref:`[text] ` section above." msgstr "" #: ../../src/man/linkcheckerrc.rst:254 msgid "dot" msgstr "" #: ../../src/man/linkcheckerrc.rst:264 msgid "csv" msgstr "" #: ../../src/man/linkcheckerrc.rst:272 #: ../../src/man/linkcheckerrc.rst:289 msgid "**separator=**\\ *CHAR*" msgstr "" #: ../../src/man/linkcheckerrc.rst:273 msgid "Set CSV separator. Default is a comma (**,**)." msgstr "" #: ../../src/man/linkcheckerrc.rst:275 msgid "**quotechar=**\\ *CHAR*" msgstr "" #: ../../src/man/linkcheckerrc.rst:275 msgid "Set CSV quote character. Default is a double quote (**\"**)." msgstr "" #: ../../src/man/linkcheckerrc.rst:278 msgid "sql" msgstr "" #: ../../src/man/linkcheckerrc.rst:286 msgid "**dbname=**\\ *STRING*" msgstr "" #: ../../src/man/linkcheckerrc.rst:287 msgid "Set database name to store into. Default is **linksdb**." msgstr "" #: ../../src/man/linkcheckerrc.rst:289 msgid "Set SQL command separator character. Default is a semicolon (**;**)." msgstr "" #: ../../src/man/linkcheckerrc.rst:292 msgid "html" msgstr "" #: ../../src/man/linkcheckerrc.rst:300 msgid "**colorbackground=**\\ *COLOR*" msgstr "" #: ../../src/man/linkcheckerrc.rst:301 msgid "Set HTML background color. Default is **#fff7e5**." msgstr "" #: ../../src/man/linkcheckerrc.rst:302 msgid "**colorurl=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:303 msgid "Set HTML URL color. Default is **#dcd5cf**." msgstr "" #: ../../src/man/linkcheckerrc.rst:304 msgid "**colorborder=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:305 msgid "Set HTML border color. Default is **#000000**." msgstr "" #: ../../src/man/linkcheckerrc.rst:306 msgid "**colorlink=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:307 msgid "Set HTML link color. Default is **#191c83**." msgstr "" #: ../../src/man/linkcheckerrc.rst:308 msgid "**colorwarning=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:309 msgid "Set HTML warning color. Default is **#e0954e**." msgstr "" #: ../../src/man/linkcheckerrc.rst:310 msgid "**colorerror=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:311 msgid "Set HTML error color. Default is **#db4930**." msgstr "" #: ../../src/man/linkcheckerrc.rst:313 msgid "**colorok=**" msgstr "" #: ../../src/man/linkcheckerrc.rst:313 msgid "Set HTML valid color. Default is **#3ba557**." msgstr "" #: ../../src/man/linkcheckerrc.rst:316 msgid "failures" msgstr "" #: ../../src/man/linkcheckerrc.rst:324 msgid "xml" msgstr "" #: ../../src/man/linkcheckerrc.rst:334 msgid "gxml" msgstr "" #: ../../src/man/linkcheckerrc.rst:344 msgid "sitemap" msgstr "" #: ../../src/man/linkcheckerrc.rst:353 msgid "**priority=**\\ *FLOAT*" msgstr "" #: ../../src/man/linkcheckerrc.rst:353 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:356 msgid "**frequency=**\\ [**always**\\ \\|\\ **hourly**\\ \\|\\ **daily**\\ \\|\\ **weekly**\\ \\|\\ **monthly**\\ \\|\\ **yearly**\\ \\|\\ **never**]" msgstr "" #: ../../src/man/linkcheckerrc.rst:356 msgid "How frequently pages are changing." msgstr "" #: ../../src/man/linkcheckerrc.rst:359 msgid "LOGGER PARTS" msgstr "" #: ../../src/man/linkcheckerrc.rst:361 msgid "**all**" msgstr "" #: ../../src/man/linkcheckerrc.rst:362 msgid "for all parts" msgstr "" #: ../../src/man/linkcheckerrc.rst:363 msgid "**id**" msgstr "" #: ../../src/man/linkcheckerrc.rst:364 msgid "a unique ID for each logentry" msgstr "" #: ../../src/man/linkcheckerrc.rst:365 msgid "**realurl**" msgstr "" #: ../../src/man/linkcheckerrc.rst:366 msgid "the full url link" msgstr "" #: ../../src/man/linkcheckerrc.rst:367 msgid "**result**" msgstr "" #: ../../src/man/linkcheckerrc.rst:368 msgid "valid or invalid, with messages" msgstr "" #: ../../src/man/linkcheckerrc.rst:369 msgid "**extern**" msgstr "" #: ../../src/man/linkcheckerrc.rst:370 msgid "1 or 0, only in some logger types reported" msgstr "" #: ../../src/man/linkcheckerrc.rst:371 msgid "**base**" msgstr "" #: ../../src/man/linkcheckerrc.rst:372 msgid "base href=..." msgstr "" #: ../../src/man/linkcheckerrc.rst:373 msgid "**name**" msgstr "" #: ../../src/man/linkcheckerrc.rst:374 msgid "name and \"name\"" msgstr "" #: ../../src/man/linkcheckerrc.rst:375 msgid "**parenturl**" msgstr "" #: ../../src/man/linkcheckerrc.rst:376 msgid "if any" msgstr "" #: ../../src/man/linkcheckerrc.rst:377 msgid "**info**" msgstr "" #: ../../src/man/linkcheckerrc.rst:378 msgid "some additional info, e.g. FTP welcome messages" msgstr "" #: ../../src/man/linkcheckerrc.rst:379 msgid "**warning**" msgstr "" #: ../../src/man/linkcheckerrc.rst:380 msgid "warnings" msgstr "" #: ../../src/man/linkcheckerrc.rst:381 msgid "**dltime**" msgstr "" #: ../../src/man/linkcheckerrc.rst:382 msgid "download time" msgstr "" #: ../../src/man/linkcheckerrc.rst:383 msgid "**checktime**" msgstr "" #: ../../src/man/linkcheckerrc.rst:384 msgid "check time" msgstr "" #: ../../src/man/linkcheckerrc.rst:385 msgid "**url**" msgstr "" #: ../../src/man/linkcheckerrc.rst:386 msgid "the original url name, can be relative" msgstr "" #: ../../src/man/linkcheckerrc.rst:387 msgid "**intro**" msgstr "" #: ../../src/man/linkcheckerrc.rst:388 msgid "the blurb at the beginning, \"starting at ...\"" msgstr "" #: ../../src/man/linkcheckerrc.rst:390 msgid "**outro**" msgstr "" #: ../../src/man/linkcheckerrc.rst:390 msgid "the blurb at the end, \"found x errors ...\"" msgstr "" #: ../../src/man/linkcheckerrc.rst:393 msgid "MULTILINE" msgstr "" #: ../../src/man/linkcheckerrc.rst:395 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:408 msgid "EXAMPLE" msgstr "" #: ../../src/man/linkcheckerrc.rst:424 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:429 msgid "AnchorCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:431 msgid "Checks validity of HTML anchors." msgstr "" #: ../../src/man/linkcheckerrc.rst:434 msgid "LocationInfo" msgstr "" #: ../../src/man/linkcheckerrc.rst:436 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:440 msgid "RegexCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:442 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:452 msgid "**warningregex=**\\ *REGEX*" msgstr "" #: ../../src/man/linkcheckerrc.rst:447 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:451 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:455 msgid "SslCertificateCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:457 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:462 msgid "**sslcertwarndays=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:462 msgid "Configures the expiration warning time in days." msgstr "" #: ../../src/man/linkcheckerrc.rst:465 msgid "HtmlSyntaxCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:467 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:471 msgid "HttpHeaderInfo" msgstr "" #: ../../src/man/linkcheckerrc.rst:473 msgid "Print HTTP headers in URL info." msgstr "" #: ../../src/man/linkcheckerrc.rst:477 msgid "**prefixes=**\\ *prefix1*\\ [,*prefix2*]..." msgstr "" #: ../../src/man/linkcheckerrc.rst:476 msgid "List of comma separated header prefixes. For example to display all HTTP headers that start with \"X-\"." msgstr "" #: ../../src/man/linkcheckerrc.rst:480 msgid "CssSyntaxCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:482 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:486 msgid "VirusCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:488 msgid "Checks the page content for virus infections with clamav. A local clamav daemon must be installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:492 msgid "**clamavconf=**\\ *filename*" msgstr "" #: ../../src/man/linkcheckerrc.rst:492 msgid "Filename of **clamd.conf** config file." msgstr "" #: ../../src/man/linkcheckerrc.rst:495 msgid "PdfParser" msgstr "" #: ../../src/man/linkcheckerrc.rst:497 msgid "Parse PDF files for URLs to check. Needs the :pypi:`pdfminer` Python package installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:501 msgid "WordParser" msgstr "" #: ../../src/man/linkcheckerrc.rst:503 msgid "Parse Word files for URLs to check. Needs the :pypi:`pywin32` Python extension installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:507 msgid "MarkdownCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:509 msgid "Parse Markdown files for URLs to check." msgstr "" #: ../../src/man/linkcheckerrc.rst:512 msgid "**filename_re=**\\ *REGEX*" msgstr "" #: ../../src/man/linkcheckerrc.rst:512 msgid "Regular expression matching the names of Markdown files." msgstr "" #: ../../src/man/linkcheckerrc.rst:515 msgid "WARNINGS" msgstr "" #: ../../src/man/linkcheckerrc.rst:517 msgid "The following warnings are recognized in the 'ignorewarnings' config file entry:" msgstr "" #: ../../src/man/linkcheckerrc.rst:520 msgid "**file-missing-slash**" msgstr "" #: ../../src/man/linkcheckerrc.rst:521 msgid "The file: URL is missing a trailing slash." msgstr "" #: ../../src/man/linkcheckerrc.rst:522 msgid "**file-system-path**" msgstr "" #: ../../src/man/linkcheckerrc.rst:523 msgid "The file: path is not the same as the system specific path." msgstr "" #: ../../src/man/linkcheckerrc.rst:524 msgid "**ftp-missing-slash**" msgstr "" #: ../../src/man/linkcheckerrc.rst:525 msgid "The ftp: URL is missing a trailing slash." msgstr "" #: ../../src/man/linkcheckerrc.rst:526 msgid "**http-cookie-store-error**" msgstr "" #: ../../src/man/linkcheckerrc.rst:527 msgid "An error occurred while storing a cookie." msgstr "" #: ../../src/man/linkcheckerrc.rst:528 msgid "**http-empty-content**" msgstr "" #: ../../src/man/linkcheckerrc.rst:529 msgid "The URL had no content." msgstr "" #: ../../src/man/linkcheckerrc.rst:530 msgid "**mail-no-mx-host**" msgstr "" #: ../../src/man/linkcheckerrc.rst:531 msgid "The mail MX host could not be found." msgstr "" #: ../../src/man/linkcheckerrc.rst:532 msgid "**nntp-no-newsgroup**" msgstr "" #: ../../src/man/linkcheckerrc.rst:533 msgid "The NNTP newsgroup could not be found." msgstr "" #: ../../src/man/linkcheckerrc.rst:534 msgid "**nntp-no-server**" msgstr "" #: ../../src/man/linkcheckerrc.rst:535 msgid "No NNTP server was found." msgstr "" #: ../../src/man/linkcheckerrc.rst:536 msgid "**url-content-size-zero**" msgstr "" #: ../../src/man/linkcheckerrc.rst:537 msgid "The URL content size is zero." msgstr "" #: ../../src/man/linkcheckerrc.rst:538 msgid "**url-content-too-large**" msgstr "" #: ../../src/man/linkcheckerrc.rst:539 msgid "The URL content size is too large." msgstr "" #: ../../src/man/linkcheckerrc.rst:540 msgid "**url-effective-url**" msgstr "" #: ../../src/man/linkcheckerrc.rst:541 msgid "The effective URL is different from the original." msgstr "" #: ../../src/man/linkcheckerrc.rst:542 msgid "**url-error-getting-content**" msgstr "" #: ../../src/man/linkcheckerrc.rst:543 msgid "Could not get the content of the URL." msgstr "" #: ../../src/man/linkcheckerrc.rst:544 msgid "**url-obfuscated-ip**" msgstr "" #: ../../src/man/linkcheckerrc.rst:545 msgid "The IP is obfuscated." msgstr "" #: ../../src/man/linkcheckerrc.rst:547 msgid "**url-whitespace**" msgstr "" #: ../../src/man/linkcheckerrc.rst:547 msgid "The URL contains leading or trailing whitespace." msgstr "" #: ../../src/man/linkcheckerrc.rst:552 msgid ":manpage:`linkchecker(1)`" msgstr "" linkchecker-10.0.1/doc/i18n/locales/000077500000000000000000000000001400504243600170175ustar00rootroot00000000000000linkchecker-10.0.1/doc/i18n/locales/de/000077500000000000000000000000001400504243600174075ustar00rootroot00000000000000linkchecker-10.0.1/doc/i18n/locales/de/LC_MESSAGES/000077500000000000000000000000001400504243600211745ustar00rootroot00000000000000linkchecker-10.0.1/doc/i18n/locales/de/LC_MESSAGES/index.po000066400000000000000000000072651400504243600226550ustar00rootroot00000000000000# 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: 2020-09-14 19:50+0100\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.8.0\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.6 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 "See the :doc:`installation document ` for more information." msgstr "" #: ../../src/index.rst:27 msgid "Basic usage" msgstr "" #: ../../src/index.rst:28 msgid "" "To check a URL like *http://www.example.org/myhomepage/* it is enough to " "execute:" msgstr "" #: ../../src/index.rst:35 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:41 msgid "Features" msgstr "" #: ../../src/index.rst:43 msgid "recursive and multithreaded checking and site crawling" msgstr "" #: ../../src/index.rst:44 msgid "" "output in colored or normal text, HTML, SQL, CSV, XML or a sitemap graph " "in different formats" msgstr "" #: ../../src/index.rst:46 msgid "" "HTTP/1.1, HTTPS, FTP, mailto:, news:, nntp:, Telnet and local file links " "support" msgstr "" #: ../../src/index.rst:48 msgid "restriction of link checking with regular expression filters for URLs" msgstr "" #: ../../src/index.rst:49 msgid "proxy support" msgstr "" #: ../../src/index.rst:50 msgid "username/password authorization for HTTP and FTP and Telnet" msgstr "" #: ../../src/index.rst:51 msgid "honors robots.txt exclusion protocol" msgstr "" #: ../../src/index.rst:52 msgid "Cookie support" msgstr "" #: ../../src/index.rst:53 msgid "HTML5 support" msgstr "" #: ../../src/index.rst:54 msgid "" ":ref:`Plugin support ` allowing custom page " "checks. Currently available are HTML and CSS syntax checks, Antivirus " "checks, and more." msgstr "" #: ../../src/index.rst:56 msgid "Different interfaces: command line and web interface" msgstr "" #: ../../src/index.rst:57 msgid "" "... and a lot more check options documented in the :doc:`man/linkchecker`" " manual page." msgstr "" #: ../../src/index.rst:61 msgid "Screenshots" msgstr "" #: ../../src/index.rst:71 msgid "Commandline interface" msgstr "" #: ../../src/index.rst:72 msgid "WSGI web interface" msgstr "" #: ../../src/index.rst:75 msgid "Test suite status" msgstr "" #: ../../src/index.rst:76 msgid "" "Linkchecker has extensive unit tests to ensure code quality. `Travis CI " "`_ is used for continuous build and test " "integration." msgstr "" #~ msgid "" #~ "#.. image:: https://travis-" #~ "ci.com/linkchecker/linkchecker.png # :alt: Build" #~ " Status # :target: https://travis-" #~ "ci.com/linkchecker/linkchecker" #~ msgstr "" linkchecker-10.0.1/doc/i18n/locales/de/LC_MESSAGES/man.po000066400000000000000000002466061400504243600223250ustar00rootroot00000000000000# 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: 2020-09-25 19:12+0100\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.8.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 msgid "" "support for HTTP/1.1, HTTPS, FTP, mailto:, news:, nntp:, Telnet 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:21 msgid "restriction of link checking with URL filters" msgstr "Einschränkung der Linküberprüfung mit URL-Filter" #: ../../src/man/linkchecker.rst:22 msgid "proxy support" msgstr "Proxy-Unterstützung" #: ../../src/man/linkchecker.rst:23 msgid "username/password authorization for HTTP, FTP and Telnet" msgstr "Benutzer/Passwort Authorisierung für HTTP, FTP und Telnet" #: ../../src/man/linkchecker.rst:24 msgid "support for robots.txt exclusion protocol" msgstr "Unterstützung des robots.txt Protokolls" #: ../../src/man/linkchecker.rst:25 msgid "support for Cookies" msgstr "Unterstützung für Cookies" #: ../../src/man/linkchecker.rst:26 msgid "support for HTML5" msgstr "Unterstützung für HTML5" #: ../../src/man/linkchecker.rst:27 msgid "HTML and CSS syntax check" msgstr "HTML- und CSS-Syntaxprüfung" #: ../../src/man/linkchecker.rst:28 msgid "Antivirus check" msgstr "Antivirusprüfung" #: ../../src/man/linkchecker.rst:29 msgid "a command line and web interface" msgstr "ein Kommandozeilenprogramm und web interface" # type: SH #: ../../src/man/linkchecker.rst:32 msgid "EXAMPLES" msgstr "BEISPIELE" # type: Plain text #: ../../src/man/linkchecker.rst:34 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:40 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:43 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:50 msgid "Checking a local HTML file on Unix:" msgstr "Überprüfung einer lokalen HTML Datei unter Unix:" # type: Plain text #: ../../src/man/linkchecker.rst:56 msgid "Checking a local HTML file on Windows:" msgstr "Überprüfung einer lokalen HTML Datei unter Windows:" # type: Plain text #: ../../src/man/linkchecker.rst:62 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:69 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:75 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:82 msgid "OPTIONS" msgstr "OPTIONEN" # type: SS #: ../../src/man/linkchecker.rst:85 msgid "General options" msgstr "Allgemeine Optionen" # type: Plain text #: ../../src/man/linkchecker.rst:89 msgid "" "Use FILENAME as configuration file. By default LinkChecker uses " "~/.linkchecker/linkcheckerrc." msgstr "" "Benutze DATEINAME als Konfigurationsdatei. Standardmäßig benutzt " "LinkChecker ~/.linkchecker/linkcheckerrc." # type: Plain text #: ../../src/man/linkchecker.rst:94 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:98 msgid "Read list of white-space separated URLs to check from stdin." msgstr "" "Lese Liste von URLs zum Prüfen von der Standardeingabe, getrennt durch " "Leerzeichen." # type: Plain text #: ../../src/man/linkchecker.rst:102 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:107 msgid "Print version and exit." msgstr "Gebe die Version aus und beende das Programm." # type: Plain text #: ../../src/man/linkchecker.rst:111 msgid "Print available check plugins and exit." msgstr "" # type: SS #: ../../src/man/linkchecker.rst:114 msgid "Output options" msgstr "Ausgabeoptionen" # type: Plain text #: ../../src/man/linkchecker.rst:118 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." #: ../../src/man/linkchecker.rst:127 msgid "" "Output to a file linkchecker-out.TYPE, $HOME/.linkchecker/failures for " "failures 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 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:143 msgid "Do not print check status messages." msgstr "Gebe keine Statusmeldungen aus." # type: Plain text #: ../../src/man/linkchecker.rst:147 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:151 msgid "" "Specify 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:161 msgid "" "Quiet operation, an alias for :option:`-o` *none*. This is only useful " "with :option:`-F`." msgstr "" "Keine Ausgabe, ein Alias für :option:`-o` *none*. Dies ist nur in " "Verbindung mit :option:`-F` nützlich." # type: Plain text #: ../../src/man/linkchecker.rst:166 msgid "Log all checked URLs. 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: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 "" "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." # type: SS #: ../../src/man/linkchecker.rst:180 msgid "Checking options" msgstr "Optionen zum Prüfen" # type: Plain text #: ../../src/man/linkchecker.rst:184 msgid "" "Read a file with initial cookie data. 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:189 msgid "Check external URLs." msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:193 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:199 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." # type: Plain text #: ../../src/man/linkchecker.rst:205 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:212 msgid "Check URLs regardless of any robots.txt files." msgstr "" # type: Plain text #: ../../src/man/linkchecker.rst:216 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:222 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:227 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:232 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:238 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: SH #: ../../src/man/linkchecker.rst:243 msgid "CONFIGURATION FILES" msgstr "KONFIGURATIONSDATEIEN" # type: Plain text #: ../../src/man/linkchecker.rst:245 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:250 msgid "OUTPUT TYPES" msgstr "AUSGABETYPEN" # type: Plain text #: ../../src/man/linkchecker.rst:252 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:256 msgid "**text**" msgstr "**text**" # type: Plain text #: ../../src/man/linkchecker.rst:257 msgid "Standard text logger, logging URLs in keyword: argument fashion." msgstr "Standard Textausgabe in \"Schlüssel: Wert\"-Form." #: ../../src/man/linkchecker.rst:260 msgid "**html**" msgstr "**html**" # type: Plain text #: ../../src/man/linkchecker.rst:259 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:262 msgid "**csv**" msgstr "**csv**" # type: Plain text #: ../../src/man/linkchecker.rst:263 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:265 msgid "**gml**" msgstr "**gml**" # type: Plain text #: ../../src/man/linkchecker.rst:265 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:268 msgid "**dot**" msgstr "**dot**" # type: Plain text #: ../../src/man/linkchecker.rst:268 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:270 msgid "**gxml**" msgstr "**gxml**" # type: Plain text #: ../../src/man/linkchecker.rst:271 msgid "Log check result as a GraphXML sitemap graph." msgstr "Gebe Prüfresultat als GraphXML-Datei aus." #: ../../src/man/linkchecker.rst:272 msgid "**xml**" msgstr "**xml**" # type: Plain text #: ../../src/man/linkchecker.rst:273 msgid "Log check result as machine-readable XML." msgstr "Gebe Prüfresultat als maschinenlesbare XML-Datei aus." #: ../../src/man/linkchecker.rst:275 msgid "**sitemap**" msgstr "**sitemap**" #: ../../src/man/linkchecker.rst:275 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:278 msgid "**sql**" msgstr "**sql**" # type: Plain text #: ../../src/man/linkchecker.rst:278 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:282 msgid "**failures**" msgstr "**failures**" # type: Plain text #: ../../src/man/linkchecker.rst:281 msgid "" "Suitable for cron jobs. Logs the check result into a file " "**~/.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:285 msgid "**none**" msgstr "**none**" # type: Plain text #: ../../src/man/linkchecker.rst:285 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:288 msgid "REGULAR EXPRESSIONS" msgstr "REGULÄRE AUSDRÜCKE" # type: Plain text #: ../../src/man/linkchecker.rst:290 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:296 msgid "COOKIE FILES" msgstr "COOKIE-DATEIEN" # type: Plain text #: ../../src/man/linkchecker.rst:298 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:301 msgid "**Host** (required)" msgstr "**Host** (erforderlich)" # type: Plain text #: ../../src/man/linkchecker.rst:302 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:303 msgid "**Path** (optional)" msgstr "**Path** (optional)" # type: Plain text #: ../../src/man/linkchecker.rst:304 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:306 msgid "**Set-cookie** (required)" msgstr "**Set-cookie** (erforderlich)" # type: Plain text #: ../../src/man/linkchecker.rst:306 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:308 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:326 msgid "PROXY SUPPORT" msgstr "PROXY UNTERSTÜTZUNG" # type: Plain text #: ../../src/man/linkchecker.rst:328 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 "" "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:338 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:344 msgid "Proxy authentication is also supported:" msgstr "Proxy-Authentifizierung wird ebenfalls unterstützt:" # type: Plain text #: ../../src/man/linkchecker.rst:350 msgid "Setting a proxy on the Windows command prompt:" msgstr "Setzen eines Proxies unter der Windows Befehlszeile:" #: ../../src/man/linkchecker.rst:357 msgid "PERFORMED CHECKS" msgstr "Durchgeführte Prüfungen" #: ../../src/man/linkchecker.rst:359 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:370 msgid "HTTP links (**http:**, **https:**)" msgstr "HTTP Verknüpfungen (**http:**, **https:**)" #: ../../src/man/linkchecker.rst:365 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:370 msgid "HTML page contents are checked for recursion." msgstr "Der Inhalt von HTML-Seiten wird rekursiv geprüft." #: ../../src/man/linkchecker.rst:377 msgid "Local files (**file:**)" msgstr "Lokale Dateien (**file:**)" #: ../../src/man/linkchecker.rst:373 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:377 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:392 msgid "Mail links (**mailto:**)" msgstr "Mail-Links (**mailto:**)" #: ../../src/man/linkchecker.rst:380 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:384 msgid "Check the address syntax, both the parts before and after the @ sign." msgstr "" #: ../../src/man/linkchecker.rst:386 msgid "Look up the MX DNS records. If we found no MX record, print an error." msgstr "" #: ../../src/man/linkchecker.rst:388 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:391 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:401 msgid "FTP links (**ftp:**)" msgstr "FTP-Links (**ftp:**)" #: ../../src/man/linkchecker.rst:395 msgid "For FTP links we do:" msgstr "Für FTP-Links wird Folgendes geprüft:" #: ../../src/man/linkchecker.rst:397 msgid "connect to the specified host" msgstr "Eine Verbindung zum angegeben Rechner wird aufgebaut" #: ../../src/man/linkchecker.rst:398 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:400 msgid "try to change to the given directory" msgstr "Versuche, in das angegebene Verzeichnis zu wechseln" #: ../../src/man/linkchecker.rst:401 msgid "list the file with the NLST command" msgstr "Liste die Dateien im Verzeichnis auf mit dem NLST-Befehl" #: ../../src/man/linkchecker.rst:405 msgid "Telnet links (**telnet:**)" msgstr "Telnet links (**telnet:**)" #: ../../src/man/linkchecker.rst:404 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." #: ../../src/man/linkchecker.rst:409 msgid "NNTP links (**news:**, **snews:**, **nntp**)" msgstr "NNTP links (**news:**, **snews:**, **nntp**)" #: ../../src/man/linkchecker.rst:408 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." #: ../../src/man/linkchecker.rst:418 msgid "Unsupported links (**javascript:**, etc.)" msgstr "Nicht unterstützte Links (**javascript:**, etc.)" #: ../../src/man/linkchecker.rst:412 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:415 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:421 ../../src/man/linkcheckerrc.rst:422 msgid "PLUGINS" msgstr "" #: ../../src/man/linkchecker.rst:423 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:433 msgid "RECURSION" msgstr "Rekursion" #: ../../src/man/linkchecker.rst:435 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:438 msgid "A URL must be valid." msgstr "Eine URL muss gültig sein." #: ../../src/man/linkchecker.rst:439 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:443 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:445 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:447 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:449 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:453 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:457 msgid "NOTES" msgstr "BEMERKUNGEN" # type: Plain text #: ../../src/man/linkchecker.rst:459 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:467 msgid "Javascript links are not supported." msgstr "Javascript Links werden nicht unterstützt." # type: Plain text #: ../../src/man/linkchecker.rst:469 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:472 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: Plain text #: ../../src/man/linkchecker.rst:474 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: SH #: ../../src/man/linkchecker.rst:478 msgid "ENVIRONMENT" msgstr "UMGEBUNG" # type: Plain text #: ../../src/man/linkchecker.rst:482 msgid "specifies default NNTP server" msgstr "gibt Standard NNTP Server an" # type: Plain text #: ../../src/man/linkchecker.rst:486 msgid "specifies default HTTP proxy server" msgstr "gibt Standard HTTP Proxy an" # type: Plain text #: ../../src/man/linkchecker.rst:490 msgid "specifies default FTP proxy server" msgstr "gibt Standard FTP Proxy an" #: ../../src/man/linkchecker.rst:494 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:498 msgid "specify output language" msgstr "gibt Ausgabesprache an" # type: SH #: ../../src/man/linkchecker.rst:501 msgid "RETURN VALUE" msgstr "RÜCKGABEWERT" # type: Plain text #: ../../src/man/linkchecker.rst:503 msgid "The return value is 2 when" msgstr "Der Rückgabewert ist 2 falls" # type: Plain text #: ../../src/man/linkchecker.rst:505 msgid "a program error occurred." msgstr "ein Programmfehler aufgetreten ist." # type: Plain text #: ../../src/man/linkchecker.rst:507 msgid "The return value is 1 when" msgstr "Der Rückgabewert ist 1 falls" # type: Plain text #: ../../src/man/linkchecker.rst:509 msgid "invalid links were found or" msgstr "ungültige Verknüpfungen gefunden wurden oder" # type: Plain text #: ../../src/man/linkchecker.rst:510 msgid "link warnings were found and warnings are enabled" msgstr "Warnungen gefunden wurden und Warnungen aktiviert sind" # type: Plain text #: ../../src/man/linkchecker.rst:512 msgid "Else the return value is zero." msgstr "Sonst ist der Rückgabewert Null." # type: SH #: ../../src/man/linkchecker.rst:515 msgid "LIMITATIONS" msgstr "LIMITIERUNGEN" # type: Plain text #: ../../src/man/linkchecker.rst:517 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:522 msgid "FILES" msgstr "DATEIEN" # type: Plain text #: ../../src/man/linkchecker.rst:524 msgid "**~/.linkchecker/linkcheckerrc** - default configuration file" msgstr "**~/.linkchecker/linkcheckerrc** - Standardkonfigurationsdatei" # type: Plain text #: ../../src/man/linkchecker.rst:526 msgid "**~/.linkchecker/failures** - default failures logger output filename" msgstr "" "**~/.linkchecker/failures** - Standard Dateiname der failures Logger " "Ausgabe" # type: Plain text #: ../../src/man/linkchecker.rst:528 msgid "**linkchecker-out.**\\ *TYPE* - default logger file output name" msgstr "**linkchecker-out.**\\ *TYP* - Standard Dateiname der Logausgabe" # type: SH #: ../../src/man/linkchecker.rst:531 ../../src/man/linkcheckerrc.rst:550 msgid "SEE ALSO" msgstr "SIEHE AUCH" # type: TH #: ../../src/man/linkchecker.rst:533 msgid ":manpage:`linkcheckerrc(5)`" msgstr ":manpage:`linkcheckerrc(5)`" # type: Plain text #: ../../src/man/linkchecker.rst:535 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:538 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 " "**~/.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." # type: SH #: ../../src/man/linkcheckerrc.rst:15 msgid "SETTINGS" msgstr "EIGENSCHAFTEN" # type: SS #: ../../src/man/linkcheckerrc.rst:18 msgid "checking" msgstr "checking" # type: TP #: ../../src/man/linkcheckerrc.rst:22 msgid "**cookiefile=**\\ *filename*" msgstr "**cookiefile=**\\ *Dateiname*" # type: Plain text #: ../../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 "" "Lese eine Datei mit Cookie-Daten. Das Cookie Datenformat wird in " ":manpage:`linkchecker(1)` erklärt. Kommandozeilenoption: " ":option:`--cookiefile`" #: ../../src/man/linkcheckerrc.rst:26 msgid "**debugmemory=**\\ [**0**\\ \\|\\ **1**]" msgstr "**debugmemory=**\\ [**0**\\ \\|\\ **1**]" #: ../../src/man/linkcheckerrc.rst:25 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:33 msgid "**localwebroot=**\\ *STRING*" msgstr "**localwebroot=**\\ *STRING*" #: ../../src/man/linkcheckerrc.rst:29 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 "**nntpserver=**\\ *STRING*" msgstr "**nntpserver=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:36 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`" # type: TP #: ../../src/man/linkcheckerrc.rst:42 msgid "**recursionlevel=**\\ *NUMBER*" msgstr "**recursionlevel=**\\ *NUMMER*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:41 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:46 msgid "**threads=**\\ *NUMBER*" msgstr "**threads=**\\ *NUMMER*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:45 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:50 msgid "**timeout=**\\ *NUMBER*" msgstr "**timeout=**\\ *NUMMER*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:49 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:55 msgid "**aborttimeout=**\\ *NUMBER*" msgstr "**aborttimeout=**\\ *NUMMER*" #: ../../src/man/linkcheckerrc.rst:53 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: TP #: ../../src/man/linkcheckerrc.rst:60 msgid "**useragent=**\\ *STRING*" msgstr "**useragent=**\\ *STRING*" #: ../../src/man/linkcheckerrc.rst:58 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:66 msgid "**sslverify=**\\ [**0**\\ \\|\\ **1**\\ \\|\\ *filename*]" msgstr "**sslverify=**\\ [**0**\\ \\|\\ **1**\\ \\|\\ *filename*]" #: ../../src/man/linkcheckerrc.rst:63 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:72 msgid "**maxrunseconds=**\\ *NUMBER*" msgstr "**maxrunseconds=**\\ *NUMMER*" #: ../../src/man/linkcheckerrc.rst:69 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:78 msgid "**maxfilesizedownload=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:75 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:82 msgid "**maxfilesizeparse=**\\ *NUMBER*" msgstr "" #: ../../src/man/linkcheckerrc.rst:81 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:87 msgid "**maxnumurls=**\\ *NUMBER*" msgstr "**maxnumurls=**\\ *NUMMER*" #: ../../src/man/linkcheckerrc.rst:85 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:90 msgid "" "Limit the maximum number of requests per second to one host. 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:100 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 "" # type: SS #: ../../src/man/linkcheckerrc.rst:103 msgid "filtering" msgstr "filtering" #: ../../src/man/linkcheckerrc.rst:106 msgid "**ignore=**\\ *REGEX* (`MULTILINE`_)" msgstr "**ignore=**\\ *REGEX* (`MULTILINE`_)" # type: Plain text #: ../../src/man/linkcheckerrc.rst:106 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:110 msgid "**ignorewarnings=**\\ *NAME*\\ [**,**\\ *NAME*...]" msgstr "**ignorewarnings=**\\ *NAME*\\ [**,**\\ *NAME*...]" # type: Plain text #: ../../src/man/linkcheckerrc.rst:109 msgid "" "Ignore the comma-separated list of warnings. See `WARNINGS`_ for the list" " of supported warnings. Command line option: none" msgstr "" "Ignoriere die kommagetrennte Liste von Warnungen. Siehe `WARNINGS`_ für " "die Liste von erkannten Warnungen. Kommandozeilenoption: none" # type: TP #: ../../src/man/linkcheckerrc.rst:114 msgid "**internlinks=**\\ *REGEX*" msgstr "**internlinks=**\\ *REGEX*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:113 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:118 msgid "**nofollow=**\\ *REGEX* (`MULTILINE`_)" msgstr "**nofollow=**\\ *REGEX* (`MULTILINE`_)" # type: Plain text #: ../../src/man/linkcheckerrc.rst:117 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:122 msgid "**checkextern=**\\ [**0**\\ \\|\\ **1**]" msgstr "**checkextern=**\\ [**0**\\ \\|\\ **1**]" #: ../../src/man/linkcheckerrc.rst:121 msgid "" "Check external links. Default is to check internal links only. Command " "line option: :option:`--check-extern`" msgstr "" # type: SS #: ../../src/man/linkcheckerrc.rst:125 msgid "authentication" msgstr "authentication" #: ../../src/man/linkcheckerrc.rst:138 msgid "**entry=**\\ *REGEX* *USER* [*PASS*] (`MULTILINE`_)" msgstr "**entry=**\\ *REGEX* *BENUTZER* [*PASSWORT*] (`MULTILINE`_)" #: ../../src/man/linkcheckerrc.rst:128 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: TP #: ../../src/man/linkcheckerrc.rst:145 msgid "**loginurl=**\\ *URL*" msgstr "**loginurl=**\\ *URL*" #: ../../src/man/linkcheckerrc.rst:141 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:147 msgid "**loginuserfield=**\\ *STRING*" msgstr "**loginuserfield=**\\ *STRING*" #: ../../src/man/linkcheckerrc.rst:148 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:149 msgid "**loginpasswordfield=**\\ *STRING*" msgstr "**loginpasswordfield=**\\ *STRING*" #: ../../src/man/linkcheckerrc.rst:150 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:155 msgid "**loginextrafields=**\\ *NAME*\\ **:**\\ *VALUE* (`MULTILINE`_)" msgstr "**loginextrafields=**\\ *NAME*\\ **:**\\ *WERT* (`MULTILINE`_)" #: ../../src/man/linkcheckerrc.rst:152 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:158 msgid "output" msgstr "output" # type: TP #: ../../src/man/linkcheckerrc.rst:164 msgid "**debug=**\\ *STRING*\\ [**,**\\ *STRING*...]" msgstr "**debug=**\\ *STRING*\\ [**,**\\ *STRING*...]" # type: Plain text #: ../../src/man/linkcheckerrc.rst:161 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`" # type: TP #: ../../src/man/linkcheckerrc.rst:172 msgid "**fileoutput=**\\ *TYPE*\\ [**,**\\ *TYPE*...]" msgstr "**fileoutput=**\\ *TYPE*\\ [**,**\\ *TYPE*...]" #: ../../src/man/linkcheckerrc.rst:167 msgid "" "Output to a file **linkchecker-out.**\\ *TYPE*, or " "**$HOME/.linkchecker/failures** for **failures** output. 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:180 msgid "**log=**\\ *TYPE*\\ [**/**\\ *ENCODING*]" msgstr "**log=**\\ *TYPE*\\ [**/**\\ *ENCODING*]" #: ../../src/man/linkcheckerrc.rst:175 msgid "" "Specify 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:184 msgid "**quiet=**\\ [**0**\\ \\|\\ **1**]" msgstr "**quiet=**\\ [**0**\\ \\|\\ **1**]" # type: Plain text #: ../../src/man/linkcheckerrc.rst:183 msgid "" "If set, operate quiet. An alias for **log=none**. This is only useful " "with **fileoutput**. Command line option: :option:`--verbose`" msgstr "" "Falls gesetzt, erfolgt keine Ausgabe. Ein Alias für **log=none**. Dies " "ist nur in Verbindung mit **fileoutput** nützlich. Kommandozeilenoption: " ":option:`--verbose`" #: ../../src/man/linkcheckerrc.rst:187 msgid "**status=**\\ [**0**\\ \\|\\ **1**]" msgstr "**status=**\\ [**0**\\ \\|\\ **1**]" # type: Plain text #: ../../src/man/linkcheckerrc.rst:187 msgid "" "Control printing check status messages. Default is 1. Command line " "option: :option:`--no-status`" msgstr "" "Kontrolle der Statusmeldungen. Standard ist 1. Kommandozeilenoption: " ":option:`--no-status`" #: ../../src/man/linkcheckerrc.rst:191 msgid "**verbose=**\\ [**0**\\ \\|\\ **1**]" msgstr "**verbose=**\\ [**0**\\ \\|\\ **1**]" # type: Plain text #: ../../src/man/linkcheckerrc.rst:190 msgid "" "If set log all checked URLs once. 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:195 msgid "**warnings=**\\ [**0**\\ \\|\\ **1**]" msgstr "**warnings=**\\ [**0**\\ \\|\\ **1**]" # type: Plain text #: ../../src/man/linkcheckerrc.rst:194 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`" # type: TP #: ../../src/man/linkcheckerrc.rst:198 msgid "text" msgstr "text" # type: TP #: ../../src/man/linkcheckerrc.rst:202 ../../src/man/linkcheckerrc.rst:246 #: ../../src/man/linkcheckerrc.rst:256 ../../src/man/linkcheckerrc.rst:266 #: ../../src/man/linkcheckerrc.rst:280 ../../src/man/linkcheckerrc.rst:294 #: ../../src/man/linkcheckerrc.rst:318 ../../src/man/linkcheckerrc.rst:326 #: ../../src/man/linkcheckerrc.rst:336 ../../src/man/linkcheckerrc.rst:346 msgid "**filename=**\\ *STRING*" msgstr "**filename=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:201 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:206 ../../src/man/linkcheckerrc.rst:248 #: ../../src/man/linkcheckerrc.rst:258 ../../src/man/linkcheckerrc.rst:268 #: ../../src/man/linkcheckerrc.rst:282 ../../src/man/linkcheckerrc.rst:296 #: ../../src/man/linkcheckerrc.rst:328 ../../src/man/linkcheckerrc.rst:338 #: ../../src/man/linkcheckerrc.rst:348 msgid "**parts=**\\ *STRING*" msgstr "**parts=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:205 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:210 ../../src/man/linkcheckerrc.rst:251 #: ../../src/man/linkcheckerrc.rst:261 ../../src/man/linkcheckerrc.rst:270 #: ../../src/man/linkcheckerrc.rst:284 ../../src/man/linkcheckerrc.rst:298 #: ../../src/man/linkcheckerrc.rst:321 ../../src/man/linkcheckerrc.rst:331 #: ../../src/man/linkcheckerrc.rst:341 ../../src/man/linkcheckerrc.rst:350 msgid "**encoding=**\\ *STRING*" msgstr "**encoding=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:209 msgid "" "Valid encodings are listed in https://docs.python.org/library/codecs.html" "#standard-encodings. Default encoding is **iso-8859-15**." 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:218 msgid "*color\\**" msgstr "*color\\**" # type: Plain text #: ../../src/man/linkcheckerrc.rst:213 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:220 msgid "**colorparent=**\\ *STRING*" msgstr "**colorparent=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:221 msgid "Set parent color. Default is **white**." msgstr "Setze Farbe des Vaters. Standard ist **white**." # type: TP #: ../../src/man/linkcheckerrc.rst:222 msgid "**colorurl=**\\ *STRING*" msgstr "**colorurl=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:223 msgid "Set URL color. Default is **default**." msgstr "Setze URL Farbe. Standard ist **default**." # type: TP #: ../../src/man/linkcheckerrc.rst:224 msgid "**colorname=**\\ *STRING*" msgstr "**colorname=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:225 msgid "Set name color. Default is **default**." msgstr "Setze Namensfarbe. Standard ist **default**." # type: TP #: ../../src/man/linkcheckerrc.rst:226 msgid "**colorreal=**\\ *STRING*" msgstr "**colorreal=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:227 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:228 msgid "**colorbase=**\\ *STRING*" msgstr "**colorbase=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:229 msgid "Set base URL color. Default is **purple**." msgstr "Setzt Basisurl Farbe. Standard ist **purple**." # type: TP #: ../../src/man/linkcheckerrc.rst:230 msgid "**colorvalid=**\\ *STRING*" msgstr "**colorvalid=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:231 msgid "Set valid color. Default is **bold;green**." msgstr "Setze gültige Farbe. Standard ist **bold;green**." # type: TP #: ../../src/man/linkcheckerrc.rst:232 msgid "**colorinvalid=**\\ *STRING*" msgstr "**colorinvalid=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:233 msgid "Set invalid color. Default is **bold;red**." msgstr "Setze ungültige Farbe. Standard ist **bold;red**." # type: TP #: ../../src/man/linkcheckerrc.rst:234 msgid "**colorinfo=**\\ *STRING*" msgstr "**colorinfo=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:235 msgid "Set info color. Default is **default**." msgstr "Setzt Informationsfarbe. Standard ist **default**." # type: TP #: ../../src/man/linkcheckerrc.rst:236 msgid "**colorwarning=**\\ *STRING*" msgstr "**colorwarning=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:237 msgid "Set warning color. Default is **bold;yellow**." msgstr "Setze Warnfarbe. Standard ist **bold;yellow**." # type: TP #: ../../src/man/linkcheckerrc.rst:238 msgid "**colordltime=**\\ *STRING*" msgstr "**colordltime=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:239 msgid "Set download time color. Default is **default**." msgstr "Setze Downloadzeitfarbe. Standard ist **default**." # type: TP #: ../../src/man/linkcheckerrc.rst:241 msgid "**colorreset=**\\ *STRING*" msgstr "**colorreset=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:241 msgid "Set reset color. Default is **default**." msgstr "Setze Reset Farbe. Standard ist **default**." # type: SS #: ../../src/man/linkcheckerrc.rst:244 msgid "gml" msgstr "gml" # type: Plain text #: ../../src/man/linkcheckerrc.rst:247 ../../src/man/linkcheckerrc.rst:249 #: ../../src/man/linkcheckerrc.rst:251 ../../src/man/linkcheckerrc.rst:257 #: ../../src/man/linkcheckerrc.rst:259 ../../src/man/linkcheckerrc.rst:261 #: ../../src/man/linkcheckerrc.rst:267 ../../src/man/linkcheckerrc.rst:269 #: ../../src/man/linkcheckerrc.rst:271 ../../src/man/linkcheckerrc.rst:281 #: ../../src/man/linkcheckerrc.rst:283 ../../src/man/linkcheckerrc.rst:285 #: ../../src/man/linkcheckerrc.rst:295 ../../src/man/linkcheckerrc.rst:297 #: ../../src/man/linkcheckerrc.rst:299 ../../src/man/linkcheckerrc.rst:319 #: ../../src/man/linkcheckerrc.rst:321 ../../src/man/linkcheckerrc.rst:327 #: ../../src/man/linkcheckerrc.rst:329 ../../src/man/linkcheckerrc.rst:331 #: ../../src/man/linkcheckerrc.rst:337 ../../src/man/linkcheckerrc.rst:339 #: ../../src/man/linkcheckerrc.rst:341 ../../src/man/linkcheckerrc.rst:347 #: ../../src/man/linkcheckerrc.rst:349 ../../src/man/linkcheckerrc.rst:351 msgid "See :ref:`[text] ` section above." msgstr "Siehe :ref:`[text] ` Sektion weiter oben." # type: SS #: ../../src/man/linkcheckerrc.rst:254 msgid "dot" msgstr "dot" # type: SS #: ../../src/man/linkcheckerrc.rst:264 msgid "csv" msgstr "csv" # type: TP #: ../../src/man/linkcheckerrc.rst:272 ../../src/man/linkcheckerrc.rst:289 msgid "**separator=**\\ *CHAR*" msgstr "**separator=**\\ *CHAR*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:273 msgid "Set CSV separator. Default is a comma (**,**)." msgstr "Das CSV Trennzeichen. Standard ist Komma (**,**)." # type: TP #: ../../src/man/linkcheckerrc.rst:275 msgid "**quotechar=**\\ *CHAR*" msgstr "**quotechar=**\\ *CHAR*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:275 msgid "Set CSV quote character. Default is a double quote (**\"**)." msgstr "" "Setze CSV Quotezeichen. Standard ist das doppelte Anführungszeichen " "(**\"**)." # type: SS #: ../../src/man/linkcheckerrc.rst:278 msgid "sql" msgstr "sql" # type: TP #: ../../src/man/linkcheckerrc.rst:286 msgid "**dbname=**\\ *STRING*" msgstr "**dbname=**\\ *STRING*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:287 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:289 msgid "Set SQL command separator character. Default is a semicolon (**;**)." msgstr "Setze SQL Kommandotrennzeichen. Standard ist ein Strichpunkt (**;**)." # type: TP #: ../../src/man/linkcheckerrc.rst:292 msgid "html" msgstr "html" # type: TP #: ../../src/man/linkcheckerrc.rst:300 msgid "**colorbackground=**\\ *COLOR*" msgstr "**colorbackground=**\\ *COLOR*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:301 msgid "Set HTML background color. Default is **#fff7e5**." msgstr "Setze HTML Hintergrundfarbe. Standard ist **#fff7e5**." # type: TP #: ../../src/man/linkcheckerrc.rst:302 msgid "**colorurl=**" msgstr "**colorurl=**" # type: Plain text #: ../../src/man/linkcheckerrc.rst:303 msgid "Set HTML URL color. Default is **#dcd5cf**." msgstr "Setze HTML URL Farbe. Standard ist **#dcd5cf**." # type: TP #: ../../src/man/linkcheckerrc.rst:304 msgid "**colorborder=**" msgstr "**colorborder=**" # type: Plain text #: ../../src/man/linkcheckerrc.rst:305 msgid "Set HTML border color. Default is **#000000**." msgstr "Setze HTML Rahmenfarbe. Standard ist **#000000**." # type: TP #: ../../src/man/linkcheckerrc.rst:306 msgid "**colorlink=**" msgstr "**colorlink=**" # type: Plain text #: ../../src/man/linkcheckerrc.rst:307 msgid "Set HTML link color. Default is **#191c83**." msgstr "Setze HTML Verknüpfungsfarbe. Standard ist **#191c83**." # type: TP #: ../../src/man/linkcheckerrc.rst:308 msgid "**colorwarning=**" msgstr "**colorwarning=**" # type: Plain text #: ../../src/man/linkcheckerrc.rst:309 msgid "Set HTML warning color. Default is **#e0954e**." msgstr "Setze HTML Warnfarbe. Standard ist **#e0954e**." # type: TP #: ../../src/man/linkcheckerrc.rst:310 msgid "**colorerror=**" msgstr "**colorerror=**" # type: Plain text #: ../../src/man/linkcheckerrc.rst:311 msgid "Set HTML error color. Default is **#db4930**." msgstr "Setze HTML Fehlerfarbe. Standard ist **#db4930**." # type: TP #: ../../src/man/linkcheckerrc.rst:313 msgid "**colorok=**" msgstr "**colorok=**" # type: Plain text #: ../../src/man/linkcheckerrc.rst:313 msgid "Set HTML valid color. Default is **#3ba557**." msgstr "Setze HTML Gültigkeitsfarbe. Standard ist **#3ba557**." #: ../../src/man/linkcheckerrc.rst:316 msgid "failures" msgstr "failures" # type: SS #: ../../src/man/linkcheckerrc.rst:324 msgid "xml" msgstr "xml" # type: TP #: ../../src/man/linkcheckerrc.rst:334 msgid "gxml" msgstr "gxml" #: ../../src/man/linkcheckerrc.rst:344 msgid "sitemap" msgstr "sitemap" # type: TP #: ../../src/man/linkcheckerrc.rst:353 msgid "**priority=**\\ *FLOAT*" msgstr "**priority=**\\ *NUMMER*" #: ../../src/man/linkcheckerrc.rst:353 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:356 msgid "" "**frequency=**\\ [**always**\\ \\|\\ **hourly**\\ \\|\\ **daily**\\ \\|\\" " **weekly**\\ \\|\\ **monthly**\\ \\|\\ **yearly**\\ \\|\\ **never**]" msgstr "" "**frequency=**\\ [**always**\\ \\|\\ **hourly**\\ \\|\\ **daily**\\ \\|\\" " **weekly**\\ \\|\\ **monthly**\\ \\|\\ **yearly**\\ \\|\\ **never**]" #: ../../src/man/linkcheckerrc.rst:356 msgid "How frequently pages are changing." msgstr "Die Häufigkeit mit der Seiten sich ändern." # type: SH #: ../../src/man/linkcheckerrc.rst:359 msgid "LOGGER PARTS" msgstr "AUSGABE PARTS" #: ../../src/man/linkcheckerrc.rst:361 msgid "**all**" msgstr "**all**" #: ../../src/man/linkcheckerrc.rst:362 msgid "for all parts" msgstr "" #: ../../src/man/linkcheckerrc.rst:363 msgid "**id**" msgstr "**id**" #: ../../src/man/linkcheckerrc.rst:364 msgid "a unique ID for each logentry" msgstr "" #: ../../src/man/linkcheckerrc.rst:365 msgid "**realurl**" msgstr "**realurl**" #: ../../src/man/linkcheckerrc.rst:366 msgid "the full url link" msgstr "" #: ../../src/man/linkcheckerrc.rst:367 msgid "**result**" msgstr "**result**" #: ../../src/man/linkcheckerrc.rst:368 msgid "valid or invalid, with messages" msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:369 msgid "**extern**" msgstr "**extern**" #: ../../src/man/linkcheckerrc.rst:370 msgid "1 or 0, only in some logger types reported" msgstr "" #: ../../src/man/linkcheckerrc.rst:371 msgid "**base**" msgstr "**base**" #: ../../src/man/linkcheckerrc.rst:372 msgid "base href=..." msgstr "base href=..." #: ../../src/man/linkcheckerrc.rst:373 msgid "**name**" msgstr "**name**" #: ../../src/man/linkcheckerrc.rst:374 msgid "name and \"name\"" msgstr "name and \"name\"" #: ../../src/man/linkcheckerrc.rst:375 msgid "**parenturl**" msgstr "**parenturl**" #: ../../src/man/linkcheckerrc.rst:376 msgid "if any" msgstr "" #: ../../src/man/linkcheckerrc.rst:377 msgid "**info**" msgstr "**info**" #: ../../src/man/linkcheckerrc.rst:378 msgid "some additional info, e.g. FTP welcome messages" msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:379 msgid "**warning**" msgstr "**warning**" # type: TP #: ../../src/man/linkcheckerrc.rst:380 msgid "warnings" msgstr "" #: ../../src/man/linkcheckerrc.rst:381 msgid "**dltime**" msgstr "**dltime**" #: ../../src/man/linkcheckerrc.rst:382 msgid "download time" msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:383 msgid "**checktime**" msgstr "**checktime**" # type: TP #: ../../src/man/linkcheckerrc.rst:384 msgid "check time" msgstr "" #: ../../src/man/linkcheckerrc.rst:385 msgid "**url**" msgstr "**url**" #: ../../src/man/linkcheckerrc.rst:386 msgid "the original url name, can be relative" msgstr "" #: ../../src/man/linkcheckerrc.rst:387 msgid "**intro**" msgstr "**intro**" #: ../../src/man/linkcheckerrc.rst:388 msgid "the blurb at the beginning, \"starting at ...\"" msgstr "" #: ../../src/man/linkcheckerrc.rst:390 msgid "**outro**" msgstr "**outro**" #: ../../src/man/linkcheckerrc.rst:390 msgid "the blurb at the end, \"found x errors ...\"" msgstr "" # type: SH #: ../../src/man/linkcheckerrc.rst:393 msgid "MULTILINE" msgstr "MULTILINE" # type: Plain text #: ../../src/man/linkcheckerrc.rst:395 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:408 msgid "EXAMPLE" msgstr "BEISPIEL" #: ../../src/man/linkcheckerrc.rst:424 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:429 msgid "AnchorCheck" msgstr "AnchorCheck" #: ../../src/man/linkcheckerrc.rst:431 msgid "Checks validity of HTML anchors." msgstr "" #: ../../src/man/linkcheckerrc.rst:434 msgid "LocationInfo" msgstr "LocationInfo" #: ../../src/man/linkcheckerrc.rst:436 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:440 msgid "RegexCheck" msgstr "RegexCheck" # type: Plain text #: ../../src/man/linkcheckerrc.rst:442 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:452 msgid "**warningregex=**\\ *REGEX*" msgstr "**warningregex=**\\ *REGEX*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:447 #, 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:451 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:455 msgid "SslCertificateCheck" msgstr "SslCertificateCheck" #: ../../src/man/linkcheckerrc.rst:457 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:462 msgid "**sslcertwarndays=**\\ *NUMBER*" msgstr "**sslcertwarndays=**\\ *NUMMER*" #: ../../src/man/linkcheckerrc.rst:462 msgid "Configures the expiration warning time in days." msgstr "" #: ../../src/man/linkcheckerrc.rst:465 msgid "HtmlSyntaxCheck" msgstr "HtmlSyntaxCheck" # type: Plain text #: ../../src/man/linkcheckerrc.rst:467 msgid "" "Check the syntax of HTML pages with the online W3C HTML validator. 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:471 msgid "HttpHeaderInfo" msgstr "HttpHeaderInfo" #: ../../src/man/linkcheckerrc.rst:473 msgid "Print HTTP headers in URL info." msgstr "" #: ../../src/man/linkcheckerrc.rst:477 msgid "**prefixes=**\\ *prefix1*\\ [,*prefix2*]..." msgstr "**prefixes=**\\ *prefix1*\\ [,*prefix2*]..." #: ../../src/man/linkcheckerrc.rst:476 msgid "" "List of comma separated header prefixes. For example to display all HTTP " "headers that start with \"X-\"." msgstr "" #: ../../src/man/linkcheckerrc.rst:480 msgid "CssSyntaxCheck" msgstr "CssSyntaxCheck" # type: Plain text #: ../../src/man/linkcheckerrc.rst:482 msgid "" "Check the syntax of HTML pages with the online W3C CSS validator. 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:486 msgid "VirusCheck" msgstr "VirusCheck" #: ../../src/man/linkcheckerrc.rst:488 msgid "" "Checks the page content for virus infections with clamav. A local clamav " "daemon must be installed." msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:492 msgid "**clamavconf=**\\ *filename*" msgstr "**clamavconf=**\\ *Dateiname*" # type: Plain text #: ../../src/man/linkcheckerrc.rst:492 msgid "Filename of **clamd.conf** config file." msgstr "Dateiname von **clamd.conf** Konfigurationsdatei." #: ../../src/man/linkcheckerrc.rst:495 msgid "PdfParser" msgstr "PdfParser" #: ../../src/man/linkcheckerrc.rst:497 msgid "" "Parse PDF files for URLs to check. Needs the :pypi:`pdfminer` Python " "package installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:501 msgid "WordParser" msgstr "WordParser" #: ../../src/man/linkcheckerrc.rst:503 msgid "" "Parse Word files for URLs to check. Needs the :pypi:`pywin32` Python " "extension installed." msgstr "" #: ../../src/man/linkcheckerrc.rst:507 msgid "MarkdownCheck" msgstr "" #: ../../src/man/linkcheckerrc.rst:509 msgid "Parse Markdown files for URLs to check." msgstr "" # type: TP #: ../../src/man/linkcheckerrc.rst:512 msgid "**filename_re=**\\ *REGEX*" msgstr "**filename_re=**\\ *REGEX*" #: ../../src/man/linkcheckerrc.rst:512 msgid "Regular expression matching the names of Markdown files." msgstr "" #: ../../src/man/linkcheckerrc.rst:515 msgid "WARNINGS" msgstr "WARNUNGEN" #: ../../src/man/linkcheckerrc.rst:517 msgid "" "The following warnings are recognized in the 'ignorewarnings' config file" " entry:" msgstr "" "Die folgenden Warnungen werden vom Konfigurationseintrag 'ignorewarnings'" " erkannt:" #: ../../src/man/linkcheckerrc.rst:520 msgid "**file-missing-slash**" msgstr "**file-missing-slash**" #: ../../src/man/linkcheckerrc.rst:521 msgid "The file: URL is missing a trailing slash." msgstr "Der file: URL fehlt ein abschließender Schrägstrich." #: ../../src/man/linkcheckerrc.rst:522 msgid "**file-system-path**" msgstr "**file-system-path**" #: ../../src/man/linkcheckerrc.rst:523 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:524 msgid "**ftp-missing-slash**" msgstr "**ftp-missing-slash**" #: ../../src/man/linkcheckerrc.rst:525 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:526 msgid "**http-cookie-store-error**" msgstr "**http-cookie-store-error**" #: ../../src/man/linkcheckerrc.rst:527 msgid "An error occurred while storing a cookie." msgstr "Ein Fehler trat auf während des Speicherns eines Cookies." #: ../../src/man/linkcheckerrc.rst:528 msgid "**http-empty-content**" msgstr "**http-empty-content**" #: ../../src/man/linkcheckerrc.rst:529 msgid "The URL had no content." msgstr "Die URL besitzt keinen Inhalt." #: ../../src/man/linkcheckerrc.rst:530 msgid "**mail-no-mx-host**" msgstr "**mail-no-mx-host**" #: ../../src/man/linkcheckerrc.rst:531 msgid "The mail MX host could not be found." msgstr "Der MX Mail-Rechner konnte nicht gefunden werden." #: ../../src/man/linkcheckerrc.rst:532 msgid "**nntp-no-newsgroup**" msgstr "**nntp-no-newsgroup**" #: ../../src/man/linkcheckerrc.rst:533 msgid "The NNTP newsgroup could not be found." msgstr "Die NNTP Nachrichtengruppe konnte nicht gefunden werden." # type: TP #: ../../src/man/linkcheckerrc.rst:534 msgid "**nntp-no-server**" msgstr "**nntp-no-server**" #: ../../src/man/linkcheckerrc.rst:535 msgid "No NNTP server was found." msgstr "Es wurde kein NNTP Server gefunden." #: ../../src/man/linkcheckerrc.rst:536 msgid "**url-content-size-zero**" msgstr "**url-content-size-zero**" #: ../../src/man/linkcheckerrc.rst:537 msgid "The URL content size is zero." msgstr "Der URL Inhaltsgrößenangabe ist Null." #: ../../src/man/linkcheckerrc.rst:538 msgid "**url-content-too-large**" msgstr "**url-content-too-large**" #: ../../src/man/linkcheckerrc.rst:539 msgid "The URL content size is too large." msgstr "Der URL Inhalt ist zu groß." #: ../../src/man/linkcheckerrc.rst:540 msgid "**url-effective-url**" msgstr "**url-effective-url**" #: ../../src/man/linkcheckerrc.rst:541 msgid "The effective URL is different from the original." msgstr "Die effektive URL unterscheidet sich vom Original." #: ../../src/man/linkcheckerrc.rst:542 msgid "**url-error-getting-content**" msgstr "**url-error-getting-content**" #: ../../src/man/linkcheckerrc.rst:543 msgid "Could not get the content of the URL." msgstr "Konnte den Inhalt der URL nicht bekommen." #: ../../src/man/linkcheckerrc.rst:544 msgid "**url-obfuscated-ip**" msgstr "**url-obfuscated-ip**" #: ../../src/man/linkcheckerrc.rst:545 msgid "The IP is obfuscated." msgstr "Die IP-Adresse ist verschleiert." #: ../../src/man/linkcheckerrc.rst:547 msgid "**url-whitespace**" msgstr "**url-whitespace**" #: ../../src/man/linkcheckerrc.rst:547 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:552 msgid ":manpage:`linkchecker(1)`" msgstr ":manpage:`linkchecker(1)`" linkchecker-10.0.1/doc/i18n/locales/fr/000077500000000000000000000000001400504243600174265ustar00rootroot00000000000000linkchecker-10.0.1/doc/i18n/locales/fr/LC_MESSAGES/000077500000000000000000000000001400504243600212135ustar00rootroot00000000000000linkchecker-10.0.1/doc/i18n/locales/fr/LC_MESSAGES/man.po000066400000000000000000002230201400504243600223250ustar00rootroot00000000000000# 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.0.1/doc/install.txt000066400000000000000000000106241400504243600170300ustar00rootroot00000000000000Installation ============ If you are upgrading from older versions of LinkChecker you should also read the upgrading documentation stored in upgrading.txt. Setup with pip ------------------ If pip_ is available, this command should install LinkChecker on the local system: ``pip3 install git+https://github.com/linkchecker/linkchecker.git`` .. _pip: https://pypi.org/project/pip/ 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 ``get-pip.py`` can be used to install pip_ (untested): https://pip.pypa.io/en/stable/installing/ Setup for GNU/Linux ------------------- On all major Linux distributions (Debian, Mandriva, Redhat, Suse, Ubuntu), the ``linkchecker`` package is available for installation. pip_ will be available, often as a package e.g. ``python3-pip``, to install the latest LinkChecker. Manual setup for Unix systems ----------------------------- First, install the required software. 1. Python >= 3.6 from https://www.python.org/ Be sure to also have installed the included distutils module. On most distributions, the distutils module is included in an extra ``python-dev`` package. 2. Python requests package from https://pypi.org/project/requests/ 3. Python Beautiful Soup package from https://pypi.org/project/beautifulsoup4/ 4. *Optional, for bash-completion:* argcomplete Python module from https://pypi.org/project/argcomplete/ 5. *Optional, for displaying country codes:* GeoIP from https://pypi.org/project/GeoIP/ 6. *Optional, used for Virus checking:* ClamAv from https://www.clamav.net/ 7. *Optional, for GNOME proxy setting parsing:* PyGObject and GIO. Best installed from your distribution e.g. ``python3-gi`` 8. *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. Now install the application. 1. Compile Python modules Run ``python setup.py sdist --manifest-only`` to create the MANIFEST file. Run ``python setup.py build`` to compile the Python files. For help about the setup.py script options, run ``python setup.py --help``. 2. a) Installation as root Run ``sudo python setup.py install`` to install LinkChecker. b) Installation as a normal user Run ``python setup.py install --home $HOME``. Note that you 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.0.1/doc/man/000077500000000000000000000000001400504243600153715ustar00rootroot00000000000000linkchecker-10.0.1/doc/man/de/000077500000000000000000000000001400504243600157615ustar00rootroot00000000000000linkchecker-10.0.1/doc/man/de/linkchecker.1000066400000000000000000000503541400504243600203340ustar00rootroot00000000000000.\" Man page generated from reStructuredText. . .TH "LINKCHECKER" "1" "Januar 28, 2021" "2021-01-28" "LinkChecker" .SH NAME linkchecker \- Kommandozeilenprogramm zum Prüfen von HTML Dokumenten und Webseiten auf ungültige Verknüpfungen . .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 .. .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 Unterstützung von HTTP/1.1, HTTPS, FTP, mailto:, news:, nntp:, Telnet und Verknüpfungen auf lokale Dateien .IP \(bu 2 Einschränkung der Linküberprüfung mit URL\-Filter .IP \(bu 2 Proxy\-Unterstützung .IP \(bu 2 Benutzer/Passwort Authorisierung für HTTP, FTP und Telnet .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 HTML\- und CSS\-Syntaxprüfung .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 Benutze DATEINAME als Konfigurationsdatei. Standardmäßig benutzt LinkChecker ~/.linkchecker/linkcheckerrc. .UNINDENT .INDENT 0.0 .TP .B \-h, \-\-help Hilfe! Gebe Gebrauchsanweisung für dieses Programm aus. .UNINDENT .INDENT 0.0 .TP .B \-\-stdin Lese Liste von URLs zum Prüfen von der Standardeingabe, getrennt durch Leerzeichen. .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 .INDENT 0.0 .TP .B \-D STRING, \-\-debug=STRING 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. .UNINDENT .INDENT 0.0 .TP .B \-F TYPE[/ENCODING][/FILENAME], \-\-file\-output=TYPE[/ENCODING][/FILENAME] 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 \fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\&. 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 \fI\%\-o\fP \fInone\fP jegliche Ausgaben auf der Konsole verhindern können. .UNINDENT .INDENT 0.0 .TP .B \-\-no\-status Gebe keine Statusmeldungen aus. .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] 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 \fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\&. .UNINDENT .INDENT 0.0 .TP .B \-q, \-\-quiet Keine Ausgabe, ein Alias für \fI\%\-o\fP \fInone\fP\&. Dies ist nur in Verbindung mit \fI\%\-F\fP nützlich. .UNINDENT .INDENT 0.0 .TP .B \-v, \-\-verbose Gebe alle geprüften URLs aus. Standard ist es, nur fehlerhafte URLs und Warnungen auszugeben. .UNINDENT .INDENT 0.0 .TP .B \-W REGEX, \-\-warning\-regex=REGEX 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 \fI\%REGULAR EXPRESSIONS\fP für weitere Infos. .UNINDENT .SS Optionen zum Prüfen .INDENT 0.0 .TP .B \-\-cookiefile=FILENAME Lese eine Datei mit Cookie\-Daten. Das Cookie Datenformat wird weiter unten erklärt. .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 \-N STRING, \-\-nntp\-server=STRING Gibt ein NNTP Rechner für news: Links. Standard ist die Umgebungsvariable \fI\%NNTP_SERVER\fP\&. Falls kein Rechner angegeben ist, wird lediglich auf korrekte Syntax des Links geprüft. .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. "Mozilla/4.0". Der Standard ist "LinkChecker/X.Y", wobei X.Y die aktuelle Version von LinkChecker ist. .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 \fBlinkcheckerrc(5)\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 "Schlüssel: Wert"\-Form. .TP \fBhtml\fP 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. .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 \fI\%https://www.sitemaps.org/protocol.html\fP 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 Für Cronjobs geeignet. Gibt das Prüfergebnis in eine Datei \fB~/.linkchecker/failures\fP aus, welche nur Einträge mit fehlerhaften URLs und die Anzahl der Fehlversuche enthält. .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 \fI\%https://docs.python.org/howto/regex.html\fP 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="smee" Set\-cookie: spam="egg" .ft P .fi .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Host: example.org Set\-cookie: baggage="elitist"; comment="hologram" .ft P .fi .UNINDENT .UNINDENT .SH PROXY UNTERSTÜTZUNG .sp Um einen Proxy unter Unix oder Windows zu benutzen, setzen Sie die \fI\%http_proxy\fP, \fBhttps_proxy\fP oder \fI\%ftp_proxy\fP Umgebungsvariablen auf die Proxy URL. Die URL sollte die Form \fBhttp://\fP[\fIuser\fP\fB:\fP\fIpass\fP\fB@\fP]\fIhost\fP[\fB:\fP\fIport\fP] 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 \fI\%no_proxy\fP Umgebungsvariable setzen, um alle Proxies für diese Domainnamen zu ignorieren. .sp Einen HTTP\-Proxy unter Unix anzugeben sieht beispielsweise so aus: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ export http_proxy="http://proxy.example.com:8080" .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="http://user1:mypass@proxy.example.org:8081" .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 \fI\%mailto:\-Link\fP 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 Telnet links (\fBtelnet:\fP) Versuche, zu dem angegeben Telnetrechner zu verginden und falls Benutzer/Passwort angegeben sind, wird versucht, sich anzumelden. .TP NNTP links (\fBnews:\fP, \fBsnews:\fP, \fBnntp\fP) 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. .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 \fI\%linkcheck/checker/unknownurl.py\fP\&. Die bekanntesten davon dürften JavaScript\-Links sein. .UNINDENT .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 \fBlinkcheckerrc(5)\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 "nofollow"\-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. .sp Beim Prüfen von \fBnews:\fP Links muß der angegebene NNTP Rechner nicht unbedingt derselbe wie der des Benutzers sein. .SH UMGEBUNG .INDENT 0.0 .TP .B NNTP_SERVER gibt Standard NNTP Server an .UNINDENT .INDENT 0.0 .TP .B http_proxy gibt Standard HTTP Proxy an .UNINDENT .INDENT 0.0 .TP .B ftp_proxy gibt Standard FTP Proxy an .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~/.linkchecker/linkcheckerrc\fP \- Standardkonfigurationsdatei .sp \fB~/.linkchecker/failures\fP \- Standard Dateiname der failures Logger Ausgabe .sp \fBlinkchecker\-out.\fP\fITYP\fP \- Standard Dateiname der Logausgabe .SH SIEHE AUCH .sp \fBlinkcheckerrc(5)\fP .sp \fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP \- gültige Ausgabe Enkodierungen .sp \fI\%https://docs.python.org/howto/regex.html\fP \- Dokumentation zu regulären Ausdrücken .SH AUTHOR Bastian Kleineidam .SH COPYRIGHT 2000-2016 Bastian Kleineidam, 2010-2021 LinkChecker Authors .\" Generated by docutils manpage writer. . linkchecker-10.0.1/doc/man/de/linkcheckerrc.5000066400000000000000000000474301400504243600206660ustar00rootroot00000000000000.\" Man page generated from reStructuredText. . .TH "LINKCHECKERRC" "5" "Januar 28, 2021" "2021-01-28" "LinkChecker" .SH NAME linkcheckerrc \- Konfigurationsdatei für LinkChecker . .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 .. .SH BESCHREIBUNG .sp \fBlinkcheckerrc\fP ist die Konfigurationsdatei für LinkChecker. Die Datei ist in einem INI\-Format geschrieben. Die Standarddatei ist \fB~/.linkchecker/linkcheckerrc\fP unter Unix\-, \fB%HOMEPATH%\elinkchecker\elinkcheckerrc\fP unter Windows\-Systemen. .SH EIGENSCHAFTEN .SS checking .INDENT 0.0 .TP \fBcookiefile=\fP\fIDateiname\fP Lese eine Datei mit Cookie\-Daten. Das Cookie Datenformat wird in \fBlinkchecker(1)\fP erklärt. Kommandozeilenoption: \fB\-\-cookiefile\fP .TP \fBdebugmemory=\fP[\fB0\fP|\fB1\fP] Write memory allocation statistics to a file on exit, requires \fI\%meliae\fP\&. 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 \fBnntpserver=\fP\fISTRING\fP Gibt ein NNTP Rechner für \fBnews:\fP Links. Standard ist die Umgebungsvariable \fBNNTP_SERVER\fP\&. Falls kein Rechner angegeben ist, wird lediglich auf korrekte Syntax des Links geprüft. Kommandozeilenoption: \fB\-\-nntp\-server\fP .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: \fB\-\-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: \fB\-\-threads\fP .TP \fBtimeout=\fP\fINUMMER\fP Setze den Timeout für TCP\-Verbindungen in Sekunden. Der Standard Timeout ist 60 Sekunden. Kommandozeilenoption: \fB\-\-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. "Mozilla/4.0". Der Standard ist "LinkChecker/X.Y", wobei X.Y die aktuelle Version von LinkChecker ist. Kommandozeilenoption: \fB\-\-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 requests per second to one host. 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: \fB\-\-no\-robots\fP .TP \fBallowedschemes=\fP\fINAME\fP[\fB,\fP\fINAME\fP\&...] Allowed URL schemes as comma\-separated list. 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: \fB\-\-ignore\-url\fP .TP \fBignorewarnings=\fP\fINAME\fP[\fB,\fP\fINAME\fP\&...] Ignoriere die kommagetrennte Liste von Warnungen. Siehe \fI\%WARNINGS\fP für die Liste von erkannten Warnungen. Kommandozeilenoption: none .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: \fB\-\-no\-follow\-url\fP .TP \fBcheckextern=\fP[\fB0\fP|\fB1\fP] Check external links. Default is to check internal links only. Command line option: \fB\-\-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 addtion to a single login page specified with \fBloginurl\fP 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 \fB\-u\fP and \fB\-p\fP match every link and therefore override the entries given here. The first match wins. Command line option: \fB\-u\fP, \fB\-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 .INDENT 0.0 .TP \fBdebug=\fP\fISTRING\fP[\fB,\fP\fISTRING\fP\&...] Gebe Testmeldungen aus für den angegebenen Logger. Verfügbare Logger sind \fBcmdline\fP, \fBchecking\fP, \fBcache\fP, \fBdns\fP, \fBthread\fP, \fBplugins\fP und \fBall\fP\&. Die Angabe \fBall\fP ist ein Synonym für alle verfügbaren Logger. Kommandozeilenoption: \fB\-\-debug\fP .TP \fBfileoutput=\fP\fITYPE\fP[\fB,\fP\fITYPE\fP\&...] Ausgabe in Datei \fBlinkchecker\-out.\fP\fITYP\fP, \fB$HOME/.linkchecker/failures\fP für \fBfailures\fP Ausgabe. Gültige Ausgabearten sind \fBtext\fP, \fBhtml\fP, \fBsql\fP, \fBcsv\fP, \fBgml\fP, \fBdot\fP, \fBxml\fP, \fBnone\fP> oder \fBfailures\fP Standard ist keine Dateiausgabe. Die verschiedenen Ausgabearten sind unten dokumentiert. Bemerke, dass man alle Konsolenausgaben mit \fBoutput=none\fP unterdrücken kann. Kommandozeilenoption: \fB\-\-file\-output\fP .TP \fBlog=\fP\fITYPE\fP[\fB/\fP\fIENCODING\fP] Gib Ausgabetyp als \fBtext\fP, \fBhtml\fP, \fBsql\fP, \fBcsv\fP, \fBgml\fP, \fBdot\fP, \fBxml\fP, \fBnone\fP oder \fBfailures\fP an. Stadard Typ ist \fBtext\fP\&. Die verschiedenen Ausgabetypen sind unten dokumentiert. Das \fIENCODING\fP gibt die Ausgabekodierung an. Der Standard ist das der lokalen Spracheinstellung. Gültige Enkodierungen sind aufgelistet unter \fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\&. Kommandozeilenoption: \fB\-\-output\fP .TP \fBquiet=\fP[\fB0\fP|\fB1\fP] Falls gesetzt, erfolgt keine Ausgabe. Ein Alias für \fBlog=none\fP\&. Dies ist nur in Verbindung mit \fBfileoutput\fP nützlich. Kommandozeilenoption: \fB\-\-verbose\fP .TP \fBstatus=\fP[\fB0\fP|\fB1\fP] Kontrolle der Statusmeldungen. Standard ist 1. Kommandozeilenoption: \fB\-\-no\-status\fP .TP \fBverbose=\fP[\fB0\fP|\fB1\fP] Falls gesetzt, gebe alle geprüften URLs einmal aus. Standard ist es, nur fehlerhafte URLs und Warnungen auszugeben. Kommandozeilenoption: \fB\-\-verbose\fP .TP \fBwarnings=\fP[\fB0\fP|\fB1\fP] Falls gesetzt, gebe keine Warnungen aus. Standard ist die Ausgabe von Warnungen. Kommandozeilenoption: \fB\-\-verbose\fP .UNINDENT .SS text .INDENT 0.0 .TP \fBfilename=\fP\fISTRING\fP Gebe Dateiname für Textausgabe an. Standard Dateiname ist \fBlinkchecker\-out.txt\fP\&. Kommandozeilenoption: \fB\-\-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 Gültige Enkodierungen sind aufgelistet unter \fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\&. Die Standardenkodierung ist \fBiso\-8859\-15\fP\&. .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 Das CSV Trennzeichen. Standard ist Komma (\fB,\fP). .TP \fBquotechar=\fP\fICHAR\fP Setze CSV Quotezeichen. Standard ist das doppelte Anführungszeichen (\fB"\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] Die Häufigkeit mit der Seiten sich ändern. .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 name .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, "starting at ..." .TP \fBoutro\fP the blurb at the end, "found x errors ..." .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. .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 "This page has moved" or "Oracle Application error". \fIREGEX\fP should be unquoted. .sp Man beachte, dass mehrere Werte in dem regulären Ausdruck kombiniert werden können, zum Beispiel "(Diese Seite ist umgezogen|Oracle Applikationsfehler)". .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 Prüfe Syntax von HTML URLs mit dem W3C Online Validator. Siehe \fI\%https://validator.w3.org/docs/api.html\fP\&. .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 "X\-". .UNINDENT .SS CssSyntaxCheck .sp Prüfe Syntax von HTML URLs mit dem W3C Online Validator. Siehe \fI\%https://jigsaw.w3.org/css\-validator/manual.html#expert\fP\&. .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 \fI\%pdfminer\fP Python package installed. .SS WordParser .sp Parse Word files for URLs to check. Needs the \fI\%pywin32\fP 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 Die folgenden Warnungen werden vom Konfigurationseintrag \(aqignorewarnings\(aq erkannt: .INDENT 0.0 .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 \fBmail\-no\-mx\-host\fP Der MX Mail\-Rechner konnte nicht gefunden werden. .TP \fBnntp\-no\-newsgroup\fP Die NNTP Nachrichtengruppe konnte nicht gefunden werden. .TP \fBnntp\-no\-server\fP Es wurde kein NNTP Server gefunden. .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\-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 \fBlinkchecker(1)\fP .SH AUTHOR Bastian Kleineidam .SH COPYRIGHT 2000-2016 Bastian Kleineidam, 2010-2021 LinkChecker Authors .\" Generated by docutils manpage writer. . linkchecker-10.0.1/doc/man/en/000077500000000000000000000000001400504243600157735ustar00rootroot00000000000000linkchecker-10.0.1/doc/man/en/linkchecker.1000066400000000000000000000442761400504243600203540ustar00rootroot00000000000000.\" Man page generated from reStructuredText. . .TH "LINKCHECKER" "1" "January 28, 2021" "2021-01-28" "LinkChecker" .SH NAME linkchecker \- command line client to check HTML documents and websites for broken links . .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 .. .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:, news:, nntp:, Telnet 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, FTP and Telnet .IP \(bu 2 support for robots.txt exclusion protocol .IP \(bu 2 support for Cookies .IP \(bu 2 support for HTML5 .IP \(bu 2 HTML and CSS syntax check .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 ~/.linkchecker/linkcheckerrc. .UNINDENT .INDENT 0.0 .TP .B \-h, \-\-help Help me! Print usage information for this program. .UNINDENT .INDENT 0.0 .TP .B \-\-stdin Read list of white\-space separated URLs to check from stdin. .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 .INDENT 0.0 .TP .B \-D STRING, \-\-debug=STRING 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. .UNINDENT .INDENT 0.0 .TP .B \-F TYPE[/ENCODING][/FILENAME], \-\-file\-output=TYPE[/ENCODING][/FILENAME] Output to a file linkchecker\-out.TYPE, $HOME/.linkchecker/failures for failures output, or FILENAME if specified. The ENCODING specifies the output encoding, the default is that of your locale. Valid encodings are listed at \fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\&. 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\-status Do not print check status messages. .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 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 \fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\&. .UNINDENT .INDENT 0.0 .TP .B \-q, \-\-quiet Quiet operation, an alias for \fI\%\-o\fP \fInone\fP\&. This is only useful with \fI\%\-F\fP\&. .UNINDENT .INDENT 0.0 .TP .B \-v, \-\-verbose Log all checked URLs. Default is to log only errors and warnings. .UNINDENT .INDENT 0.0 .TP .B \-W REGEX, \-\-warning\-regex=REGEX 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 \fI\%REGULAR EXPRESSIONS\fP for more info. .UNINDENT .SS Checking options .INDENT 0.0 .TP .B \-\-cookiefile=FILENAME Read a file with initial cookie data. 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 \-N STRING, \-\-nntp\-server=STRING Specify an NNTP server for news: links. Default is the environment variable \fI\%NNTP_SERVER\fP\&. If no host is given, only the syntax of the link is checked. .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 "Mozilla/4.0". The default is "LinkChecker/X.Y" where X.Y is the current version of LinkChecker. .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 \fBlinkcheckerrc(5)\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 \fI\%https://www.sitemaps.org/protocol.html\fP\&. .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~/.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 \fI\%https://docs.python.org/howto/regex.html\fP 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="smee" Set\-cookie: spam="egg" .ft P .fi .UNINDENT .UNINDENT .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Host: example.org Set\-cookie: baggage="elitist"; comment="hologram" .ft P .fi .UNINDENT .UNINDENT .SH PROXY SUPPORT .sp To use a proxy on Unix or Windows set the \fI\%http_proxy\fP, \fBhttps_proxy\fP or \fI\%ftp_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, 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 \fI\%no_proxy\fP environment variables to ignore any proxy settings for these domains. .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="http://proxy.example.com:8080" .ft P .fi .UNINDENT .UNINDENT .sp Proxy authentication is also supported: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ export http_proxy="http://user1:mypass@proxy.example.org:8081" .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 Telnet links (\fBtelnet:\fP) We try to connect and if user/password are given, login to the given telnet server. .TP NNTP links (\fBnews:\fP, \fBsnews:\fP, \fBnntp\fP) We try to connect to the given NNTP server. If a news group or article is specified, try to request it from the server. .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 \fI\%linkcheck/checker/unknownurl.py\fP source file. The most prominent of them should be JavaScript links. .UNINDENT .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 \fBlinkcheckerrc(5)\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 "nofollow" 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. .sp When checking \fBnews:\fP links the given NNTP host doesn\(aqt need to be the same as the host of the user browsing your pages. .SH ENVIRONMENT .INDENT 0.0 .TP .B NNTP_SERVER specifies default NNTP server .UNINDENT .INDENT 0.0 .TP .B http_proxy specifies default HTTP proxy server .UNINDENT .INDENT 0.0 .TP .B ftp_proxy specifies default FTP proxy server .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~/.linkchecker/linkcheckerrc\fP \- default configuration file .sp \fB~/.linkchecker/failures\fP \- default failures logger output filename .sp \fBlinkchecker\-out.\fP\fITYPE\fP \- default logger file output name .SH SEE ALSO .sp \fBlinkcheckerrc(5)\fP .sp \fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP \- valid output encodings .sp \fI\%https://docs.python.org/howto/regex.html\fP \- regular expression documentation .SH AUTHOR Bastian Kleineidam .SH COPYRIGHT 2000-2016 Bastian Kleineidam, 2010-2021 LinkChecker Authors .\" Generated by docutils manpage writer. . linkchecker-10.0.1/doc/man/en/linkcheckerrc.5000066400000000000000000000455321400504243600207010ustar00rootroot00000000000000.\" Man page generated from reStructuredText. . .TH "LINKCHECKERRC" "5" "January 28, 2021" "2021-01-28" "LinkChecker" .SH NAME linkcheckerrc \- configuration file for LinkChecker . .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 .. .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~/.linkchecker/linkcheckerrc\fP on Unix, \fB%HOMEPATH%\e.linkchecker\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 \fBlinkchecker(1)\fP\&. Command line option: \fB\-\-cookiefile\fP .TP \fBdebugmemory=\fP[\fB0\fP|\fB1\fP] Write memory allocation statistics to a file on exit, requires \fI\%meliae\fP\&. 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 \fBnntpserver=\fP\fISTRING\fP Specify an NNTP server for \fBnews:\fP links. Default is the environment variable \fBNNTP_SERVER\fP\&. If no host is given, only the syntax of the link is checked. Command line option: \fB\-\-nntp\-server\fP .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: \fB\-\-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: \fB\-\-threads\fP .TP \fBtimeout=\fP\fINUMBER\fP Set the timeout for connection attempts in seconds. The default timeout is 60 seconds. Command line option: \fB\-\-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 "Mozilla/4.0". The default is "LinkChecker/X.Y" where X.Y is the current version of LinkChecker. Command line option: \fB\-\-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 requests per second to one host. 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: \fB\-\-no\-robots\fP .TP \fBallowedschemes=\fP\fINAME\fP[\fB,\fP\fINAME\fP\&...] Allowed URL schemes as comma\-separated list. 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: \fB\-\-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. Command line option: none .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: \fB\-\-no\-follow\-url\fP .TP \fBcheckextern=\fP[\fB0\fP|\fB1\fP] Check external links. Default is to check internal links only. Command line option: \fB\-\-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 addtion to a single login page specified with \fBloginurl\fP 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 \fB\-u\fP and \fB\-p\fP match every link and therefore override the entries given here. The first match wins. Command line option: \fB\-u\fP, \fB\-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 .INDENT 0.0 .TP \fBdebug=\fP\fISTRING\fP[\fB,\fP\fISTRING\fP\&...] Print debugging output for the given modules. Available debug modules are \fBcmdline\fP, \fBchecking\fP, \fBcache\fP, \fBdns\fP, \fBthread\fP, \fBplugins\fP and \fBall\fP\&. Specifying \fBall\fP is an alias for specifying all available loggers. Command line option: \fB\-\-debug\fP .TP \fBfileoutput=\fP\fITYPE\fP[\fB,\fP\fITYPE\fP\&...] Output to a file \fBlinkchecker\-out.\fP\fITYPE\fP, or \fB$HOME/.linkchecker/failures\fP for \fBfailures\fP output. 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: \fB\-\-file\-output\fP .TP \fBlog=\fP\fITYPE\fP[\fB/\fP\fIENCODING\fP] Specify 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 \fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\&. Command line option: \fB\-\-output\fP .TP \fBquiet=\fP[\fB0\fP|\fB1\fP] If set, operate quiet. An alias for \fBlog=none\fP\&. This is only useful with \fBfileoutput\fP\&. Command line option: \fB\-\-verbose\fP .TP \fBstatus=\fP[\fB0\fP|\fB1\fP] Control printing check status messages. Default is 1. Command line option: \fB\-\-no\-status\fP .TP \fBverbose=\fP[\fB0\fP|\fB1\fP] If set log all checked URLs once. Default is to log only errors and warnings. Command line option: \fB\-\-verbose\fP .TP \fBwarnings=\fP[\fB0\fP|\fB1\fP] If set log warnings. Default is to log warnings. Command line option: \fB\-\-no\-warnings\fP .UNINDENT .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: \fB\-\-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 \fI\%https://docs.python.org/library/codecs.html#standard\-encodings\fP\&. Default encoding is \fBiso\-8859\-15\fP\&. .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 comma (\fB,\fP). .TP \fBquotechar=\fP\fICHAR\fP Set CSV quote character. Default is a double quote (\fB"\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. .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 name .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, "starting at ..." .TP \fBoutro\fP the blurb at the end, "found x errors ..." .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. .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 "This page has moved" or "Oracle Application error". \fIREGEX\fP should be unquoted. .sp Note that multiple values can be combined in the regular expression, for example "(This page has moved|Oracle Application error)". .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 with the online W3C HTML validator. See \fI\%https://validator.w3.org/docs/api.html\fP\&. .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 "X\-". .UNINDENT .SS CssSyntaxCheck .sp Check the syntax of HTML pages with the online W3C CSS validator. See \fI\%https://jigsaw.w3.org/css\-validator/manual.html#expert\fP\&. .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 \fI\%pdfminer\fP Python package installed. .SS WordParser .sp Parse Word files for URLs to check. Needs the \fI\%pywin32\fP 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 in the \(aqignorewarnings\(aq config file entry: .INDENT 0.0 .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 \fBmail\-no\-mx\-host\fP The mail MX host could not be found. .TP \fBnntp\-no\-newsgroup\fP The NNTP newsgroup could not be found. .TP \fBnntp\-no\-server\fP No NNTP server was 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\-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 \fBlinkchecker(1)\fP .SH AUTHOR Bastian Kleineidam .SH COPYRIGHT 2000-2016 Bastian Kleineidam, 2010-2021 LinkChecker Authors .\" Generated by docutils manpage writer. . linkchecker-10.0.1/doc/robots.txt.example000066400000000000000000000004701400504243600203220ustar00rootroot00000000000000# 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.0.1/doc/src/000077500000000000000000000000001400504243600154055ustar00rootroot00000000000000linkchecker-10.0.1/doc/src/Makefile000066400000000000000000000020421400504243600170430ustar00rootroot00000000000000# You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build SPHINXINTL ?= sphinx-intl 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 $(SPHINXOPTS) $(O) man/* 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.0.1/doc/src/_templates/000077500000000000000000000000001400504243600175425ustar00rootroot00000000000000linkchecker-10.0.1/doc/src/_templates/layout.html000066400000000000000000000005071400504243600217470ustar00rootroot00000000000000{% extends "!layout.html" %} {% block menu %} {{ super() }} Index
Change Log Issue Tracker {% endblock %} linkchecker-10.0.1/doc/src/code/000077500000000000000000000000001400504243600163175ustar00rootroot00000000000000linkchecker-10.0.1/doc/src/code/index.rst000066400000000000000000000124111400504243600201570ustar00rootroot00000000000000:github_url: https://github.com/linkchecker/linkchecker/blob/master/doc/src/code/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="NntpUrl", shape="record", href="../code/linkcheck/linkcheck.checker.nntpurl.html", target="_blank"]; "10" [label="ProxySupport", shape="record", href="../code/linkcheck/linkcheck.checker.proxysupport.html", target="_blank"]; "11" [label="TelnetUrl", shape="record", href="../code/linkcheck/linkcheck.checker.telneturl.html", target="_blank"]; "12" [label="UnknownUrl", shape="record", href="../code/linkcheck/linkcheck.checker.unknownurl.html", target="_blank"]; "13" [label="UrlBase", shape="record", href="../code/linkcheck/linkcheck.checker.urlbase.html", target="_blank"]; "1" -> "13" [arrowhead="empty", arrowtail="none"]; "2" -> "13" [arrowhead="empty", arrowtail="none"]; "3" -> "6" [arrowhead="empty", arrowtail="none"]; "3" -> "10" [arrowhead="empty", arrowtail="none"]; "4" -> "6" [arrowhead="empty", arrowtail="none"]; "4" -> "10" [arrowhead="empty", arrowtail="none"]; "5" -> "12" [arrowhead="empty", arrowtail="none"]; "6" -> "13" [arrowhead="empty", arrowtail="none"]; "7" -> "13" [arrowhead="empty", arrowtail="none"]; "8" -> "13" [arrowhead="empty", arrowtail="none"]; "9" -> "13" [arrowhead="empty", arrowtail="none"]; "11" -> "13" [arrowhead="empty", arrowtail="none"]; "12" -> "13" [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.0.1/doc/src/code_of_conduct.rst000066400000000000000000000000471400504243600212550ustar00rootroot00000000000000.. include:: ../../CODE_OF_CONDUCT.rst linkchecker-10.0.1/doc/src/conf.py000066400000000000000000000044101400504243600167030ustar00rootroot00000000000000import os import sys sys.path.insert(0, os.path.abspath('../..')) # -- Project information ----------------------------------------------------- from datetime import date import linkcheck.configuration project = 'LinkChecker' copyright = linkcheck.configuration.Copyright.split("Copyright (C) ")[1] version = str(date.today()) 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', ] 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 extlinks = {'pypi': ('https://pypi.org/project/%s/', '')} graphviz_output_format = 'svg' # -- Mock -------------------------------------------------------------------- import linkcheck.logger linkcheck.logger.failures.FailuresLogger.LoggerArgs = { 'filename': '~/.linkchecker/failures'} linkchecker-10.0.1/doc/src/contributing.rst000066400000000000000000000000441400504243600206440ustar00rootroot00000000000000.. include:: ../../CONTRIBUTING.rst linkchecker-10.0.1/doc/src/faq.rst000066400000000000000000000106051400504243600167100ustar00rootroot00000000000000: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 of 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 of 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, https_proxy, ftp_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.0.1/doc/src/images/000077500000000000000000000000001400504243600166525ustar00rootroot00000000000000linkchecker-10.0.1/doc/src/images/favicon.ico000066400000000000000000000070661400504243600210040ustar00rootroot00000000000000h& ( @ʅ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.0.1/doc/src/images/logo128x128.png000066400000000000000000000637721400504243600212150ustar00rootroot00000000000000PNG  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.0.1/doc/src/images/shot1.png000066400000000000000000000274731400504243600204330ustar00rootroot00000000000000PNG  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.6 or later. Visit the project on `GitHub `_. Installation ------------ .. code-block:: console $ pip3 install git+https://github.com/linkchecker/linkchecker.git See the :doc:`installation document ` for more information. 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:, news:, nntp:, Telnet and local file links support - restriction of link checking with regular expression filters for URLs - proxy support - username/password authorization for HTTP and FTP and Telnet - honors robots.txt exclusion protocol - Cookie support - HTML5 support - :ref:`Plugin support ` allowing custom page checks. Currently available are HTML and CSS syntax checks, Antivirus checks, and more. - 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. `Travis CI `_ is used for continuous build and test integration. .. image:: https://travis-ci.com/linkchecker/linkchecker.png :alt: Build Status :target: https://travis-ci.com/linkchecker/linkchecker .. toctree:: :hidden: faq install upgrading man/linkchecker man/linkcheckerrc contributing code_of_conduct code/index linkchecker-10.0.1/doc/src/install.rst000066400000000000000000000003161400504243600176050ustar00rootroot00000000000000Installation ============ 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.0.1/doc/src/man/000077500000000000000000000000001400504243600161605ustar00rootroot00000000000000linkchecker-10.0.1/doc/src/man/linkchecker.rst000066400000000000000000000406171400504243600212040ustar00rootroot00000000000000:github_url: https://github.com/linkchecker/linkchecker/blob/master/doc/src/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:, news:, nntp:, Telnet and local file links - restriction of link checking with URL filters - proxy support - username/password authorization for HTTP, FTP and Telnet - support for robots.txt exclusion protocol - support for Cookies - support for HTML5 - HTML and CSS syntax check - 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 ~/.linkchecker/linkcheckerrc. .. option:: -h, --help Help me! Print usage information for this program. .. option:: --stdin Read list of white-space separated URLs to check from stdin. .. 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 ^^^^^^^^^^^^^^ .. option:: -D STRING, --debug=STRING 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. .. option:: -F TYPE[/ENCODING][/FILENAME], --file-output=TYPE[/ENCODING][/FILENAME] Output to a file linkchecker-out.TYPE, $HOME/.linkchecker/failures for failures 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 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-status Do not print check status messages. .. option:: --no-warnings Don't log warnings. Default is to log warnings. .. option:: -o TYPE[/ENCODING], --output=TYPE[/ENCODING] Specify 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:: -q, --quiet Quiet operation, an alias for :option:`-o` *none*. This is only useful with :option:`-F`. .. option:: -v, --verbose Log all checked URLs. Default is to log only errors and warnings. .. option:: -W REGEX, --warning-regex=REGEX 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. Checking options ^^^^^^^^^^^^^^^^ .. option:: --cookiefile=FILENAME Read a file with initial cookie data. 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:: -N STRING, --nntp-server=STRING 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. .. 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. 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 **~/.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`, :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. 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 Telnet links (**telnet:**) We try to connect and if user/password are given, login to the given telnet server. NNTP links (**news:**, **snews:**, **nntp**) We try to connect to the given NNTP server. If a news group or article is specified, try to request it from the server. 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. 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. When checking **news:** links the given NNTP host doesn't need to be the same as the host of the user browsing your pages. ENVIRONMENT ----------- .. envvar:: NNTP_SERVER specifies default NNTP server .. envvar:: http_proxy specifies default HTTP proxy server .. envvar:: ftp_proxy specifies default FTP proxy server .. 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 ----- **~/.linkchecker/linkcheckerrc** - default configuration file **~/.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.0.1/doc/src/man/linkcheckerrc.rst000066400000000000000000000437611400504243600215340ustar00rootroot00000000000000:github_url: https://github.com/linkchecker/linkchecker/blob/master/doc/src/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 **~/.linkchecker/linkcheckerrc** on Unix, **%HOMEPATH%\\.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 **nntpserver=**\ *STRING* 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` **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 requests per second to one host. 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 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. Command line option: none **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 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` **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 ^^^^^^ **debug=**\ *STRING*\ [**,**\ *STRING*...] 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` **fileoutput=**\ *TYPE*\ [**,**\ *TYPE*...] Output to a file **linkchecker-out.**\ *TYPE*, or **$HOME/.linkchecker/failures** for **failures** output. 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 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` **quiet=**\ [**0**\ \|\ **1**] If set, operate quiet. An alias for **log=none**. This is only useful with **fileoutput**. Command line option: :option:`--verbose` **status=**\ [**0**\ \|\ **1**] Control printing check status messages. Default is 1. Command line option: :option:`--no-status` **verbose=**\ [**0**\ \|\ **1**] If set log all checked URLs once. 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` 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 **iso-8859-15**. *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 comma (**,**). **quotechar=**\ *CHAR* Set CSV quote character. Default is a double quote (**"**). 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. 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. 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 with the online W3C HTML validator. See https://validator.w3.org/docs/api.html. 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 HTML pages with the online W3C CSS validator. 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` 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 in the 'ignorewarnings' config file entry: **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. **mail-no-mx-host** The mail MX host could not be found. **nntp-no-newsgroup** The NNTP newsgroup could not be found. **nntp-no-server** No NNTP server was found. **url-content-size-zero** The URL content size is zero. **url-content-too-large** The URL content size is too large. **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.0.1/doc/src/upgrading.rst000066400000000000000000000000361400504243600201160ustar00rootroot00000000000000.. include:: ../upgrading.txt linkchecker-10.0.1/doc/translations.md000066400000000000000000000015741400504243600176700ustar00rootroot00000000000000LinkChecker Translations ======================== Translations for the application are stored in po/. Translations for the man pages are stored in doc/. Application Translations ------------------------ ``linkchecker $ make locale`` is equivalent to: ``linkchecker/po $ make`` Man Page Translations --------------------- Sphinx is used to generate .pot and .po (with sphinx-intl) files in i18n/ and man pages in man/. 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.0.1/doc/upgrading.txt000066400000000000000000000226141400504243600173440ustar00rootroot00000000000000Upgrading ========= 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.0.1/install-rpm.sh000066400000000000000000000021361400504243600166510ustar00rootroot00000000000000python setup.py install --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES # 'brp-compress' compresses the manpages without distutils knowing. # The sed scripts append ".gz", ".bz2" or ".xz" suffixes to the affected # manpage filenames. RPM_MANDIR=usr/share/man RPM_LOCALMANDIR=usr/local/share/man if [ -n "$( ls $RPM_BUILD_ROOT/$RPM_MANDIR/man*/*.bz2 2>/dev/null )" \ -o -n "$( ls $RPM_BUILD_ROOT/$RPM_LOCALMANDIR/man*/*.bz2 2>/dev/null )" ]; then # add .bz2 suffix sed -i -e 's@man/man\([[:digit:]]\)/\(.\+\.[[:digit:]]\)$@man/man\1/\2.bz2@g' INSTALLED_FILES elif [ -n "$( ls $RPM_BUILD_ROOT/$RPM_MANDIR/man*/*.xz 2>/dev/null )" \ -o -n "$( ls $RPM_BUILD_ROOT/$RPM_LOCALMANDIR/man*/*.xz 2>/dev/null )" ]; then # add .xz suffix sed -i -e 's@man/man\([[:digit:]]\)/\(.\+\.[[:digit:]]\)$@man/man\1/\2.xz@g' INSTALLED_FILES elif [ -n "$( ls $RPM_BUILD_ROOT/$RPM_MANDIR/man*/*.gz 2>/dev/null )" \ -o -n "$( ls $RPM_BUILD_ROOT/$RPM_LOCALMANDIR/man*/*.gz 2>/dev/null )" ]; then # add .gz suffix sed -i -e 's@man/man\([[:digit:]]\)/\(.\+\.[[:digit:]]\)$@man/man\1/\2.gz@g' INSTALLED_FILES fi linkchecker-10.0.1/linkcheck/000077500000000000000000000000001400504243600160045ustar00rootroot00000000000000linkchecker-10.0.1/linkcheck/__init__.py000066400000000000000000000113401400504243600201140ustar00rootroot00000000000000# 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, 6, 0, 'final', 0): import platform raise SystemExit( "This program requires Python 3.6 or later instead of %s." % platform.python_version() ) import os import re import signal import traceback from . import i18n, log from .logconf import ( LOG_ROOT, LOG_CMDLINE, LOG_CHECK, LOG_CACHE, LOG_THREAD, LOG_PLUGIN, ) import _LinkChecker_configdata as configdata def module_path(): """Return absolute directory of system executable.""" return os.path.dirname(os.path.abspath(sys.executable)) def get_install_data(): """Return absolute path of LinkChecker data installation directory.""" from .loader import is_frozen if is_frozen(): return module_path() return configdata.install_data 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(loc=None): """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: locdir = os.path.join(get_install_data(), 'share', 'locale') i18n.init(configdata.name.lower(), locdir, loc=loc) # 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() 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]) 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 ***") linkchecker-10.0.1/linkcheck/ansicolor.py000066400000000000000000000224231400504243600203520ustar00rootroot00000000000000# 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, } # 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.0.1/linkcheck/better_exchook2.py000066400000000000000000000222251400504243600214500ustar00rootroot00000000000000# # 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 = "%s: %s" % (etype, valuestr) return line if (isinstance(etype, BaseException) or (hasattr(types, "InstanceType") and isinstance(etype, types.InstanceType)) 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.0.1/linkcheck/bookmarks/000077500000000000000000000000001400504243600177745ustar00rootroot00000000000000linkchecker-10.0.1/linkcheck/bookmarks/__init__.py000066400000000000000000000013571400504243600221130ustar00rootroot00000000000000# 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.0.1/linkcheck/bookmarks/chromium.py000066400000000000000000000027711400504243600222000ustar00rootroot00000000000000# 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. """ for url, name in parse_bookmark_json(json.loads(data)): yield url, name def parse_bookmark_json(data): """Parse complete JSON data for Chromium Bookmarks.""" for entry in data["roots"].values(): for url, name in parse_bookmark_node(entry): yield url, name 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"]: for entry in parse_bookmark_node(child): yield entry linkchecker-10.0.1/linkcheck/bookmarks/firefox.py000066400000000000000000000032321400504243600220100ustar00rootroot00000000000000# 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.0.1/linkcheck/bookmarks/opera.py000066400000000000000000000023561400504243600214620ustar00rootroot00000000000000# 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.0.1/linkcheck/bookmarks/safari.py000066400000000000000000000036521400504243600216210ustar00rootroot00000000000000# 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]: for item in parse_plist(child): yield item 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.0.1/linkcheck/cache/000077500000000000000000000000001400504243600170475ustar00rootroot00000000000000linkchecker-10.0.1/linkcheck/cache/__init__.py000066400000000000000000000014761400504243600211700ustar00rootroot00000000000000# 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.0.1/linkcheck/cache/results.py000066400000000000000000000044331400504243600211260ustar00rootroot00000000000000# 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, max_size=100000): """Initialize result cache.""" # mapping {URL -> cached result} self.cache = {} self.max_size = max_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.0.1/linkcheck/cache/robots_txt.py000066400000000000000000000060331400504243600216320ustar00rootroot00000000000000# 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. """ from .. import robotparser2 from ..containers import LFUCache from ..decorators import synchronized from ..lock import get_lock # 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) if hasattr(url_data, "proxy") and hasattr(url_data, "proxy_type"): kwargs["proxies"] = {url_data.proxytype: url_data.proxy} 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: url_data.add_url(sitemap_url, line=line) @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.0.1/linkcheck/cache/urlqueue.py000066400000000000000000000207121400504243600212720ustar00rootroot00000000000000# 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.notifyAll() 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.notifyAll() 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.0.1/linkcheck/checker/000077500000000000000000000000001400504243600174105ustar00rootroot00000000000000linkchecker-10.0.1/linkcheck/checker/__init__.py000066400000000000000000000140051400504243600215210ustar00rootroot00000000000000# 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().startswith("www."): # syntactic sugar return "http://%s" % url elif url.lower().startswith("ftp."): # syntactic sugar return "ftp://%s" % 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 seperator 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) 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 == "telnet": klass = telneturl.TelnetUrl elif scheme == "mailto": klass = mailtourl.MailtoUrl elif scheme in ("nntp", "news", "snews"): klass = nntpurl.NntpUrl 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 KeyError: # Some unicode entries raise KeyError. url = name lines.append('%s' % (url, name)) lines.extend(["", ""]) return os.linesep.join(lines) # all the URL classes from . import ( # noqa: E402 fileurl, unknownurl, ftpurl, httpurl, dnsurl, mailtourl, telneturl, nntpurl, ignoreurl, itmsservicesurl, ) linkchecker-10.0.1/linkcheck/checker/const.py000066400000000000000000000104701400504243600211120ustar00rootroot00000000000000# 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 select import nntplib 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, socket.error, select.error, # nttp errors (including EOFError) nntplib.NNTPError, EOFError, # http errors requests.exceptions.RequestException, requests.packages.urllib3.exceptions.HTTPError, # 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_OBFUSCATED_IP = "url-obfuscated-ip" WARN_URL_RATE_LIMITED = "url-rate-limited" 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_FTP_MISSING_SLASH = "ftp-missing-slash" WARN_HTTP_EMPTY_CONTENT = "http-empty-content" WARN_HTTP_COOKIE_STORE_ERROR = "http-cookie-store-error" WARN_IGNORE_URL = "ignore-url" WARN_MAIL_NO_MX_HOST = "mail-no-mx-host" WARN_NNTP_NO_SERVER = "nntp-no-server" WARN_NNTP_NO_NEWSGROUP = "nntp-no-newsgroup" 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_RATE_LIMITED: _( "The URL request was rate limited so need reduce number of requests." ), 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_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_IGNORE_URL: _("The URL has been ignored."), WARN_MAIL_NO_MX_HOST: _("The mail MX host could not be found."), WARN_NNTP_NO_SERVER: _("No NNTP server was found."), WARN_NNTP_NO_NEWSGROUP: _("The NNTP newsgroup could not be found."), WARN_URL_OBFUSCATED_IP: _("The IP is obfuscated."), WARN_XML_PARSE_ERROR: _("XML could not be parsed."), } linkchecker-10.0.1/linkcheck/checker/dnsurl.py000066400000000000000000000027641400504243600213020ustar00rootroot00000000000000# 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.0.1/linkcheck/checker/fileurl.py000066400000000000000000000252611400504243600214320ustar00rootroot00000000000000# 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 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 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. from .urlbase import url_norm # norm base url - can raise UnicodeError from url.idna_encode() base_url, is_idn = url_norm(self.base_url, self.encoding) urlparts = list(urllib.parse.urlsplit(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.utcfromtimestamp(fileutil.get_mtime(filename)) 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())) data = data.encode("iso8859-1", "ignore") 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 if self.content_type in self.ContentMimetypes: return True log.debug( LOG_CHECK, "File with content type %r is not parseable.", self.content_type ) return False def set_content_type(self): """Return 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 = "" 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) linkchecker-10.0.1/linkcheck/checker/ftpurl.py000066400000000000000000000173211400504243600213020ustar00rootroot00000000000000# 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 StringIO from .. import log, LOG_CHECK, LinkCheckerError, mimeutil from . import proxysupport, httpurl, internpaturl, get_index_html from .const import WARN_FTP_MISSING_SLASH class FtpUrl(internpaturl.InternPatternUrl, proxysupport.ProxySupport): """ 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): """ In case of proxy, delegate to HttpUrl. Else check in this order: login, changing directory, list the file. """ # proxy support (we support only http) self.set_proxy(self.aggregate.config["proxy"].get(self.scheme)) if self.proxy: # using a (HTTP) proxy http = httpurl.HttpUrl( self.base_url, self.recursion_level, self.aggregate, parent_url=self.parent_url, base_ref=self.base_ref, line=self.line, column=self.column, name=self.name, ) http.build_url() return http.check() 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 "%s/" % 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 if self.content_type in self.ContentMimetypes: return True log.debug( LOG_CHECK, "URL with content type %r is not parseable.", self.content_type ) return False 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) 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 = "RETR %s" % self.filename buf = StringIO() def stor_data(s): """Helper method storing given data""" # limit the download size if (buf.tell() + len(s)) > self.max_size: 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.0.1/linkcheck/checker/httpurl.py000066400000000000000000000334701400504243600214730ustar00rootroot00000000000000# 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( '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, proxysupport # import warnings from .const import WARN_HTTP_EMPTY_CONTENT, WARN_URL_RATE_LIMITED from requests.sessions import REDIRECT_STATI # assumed HTTP header encoding HEADER_ENCODING = "iso-8859-1" HTTP_SCHEMAS = ('http://', 'https://') # match for robots meta element content attribute nofollow_re = re.compile(r"\bnofollow\b", re.IGNORECASE) class HttpUrl(internpaturl.InternPatternUrl, proxysupport.ProxySupport): """ 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() # set the proxy, so a 407 status after this is an error self.set_proxy(self.aggregate.config["proxy"].get(self.scheme)) 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 self.encoding = self.url_connection.encoding log.debug(LOG_CHECK, "Response encoding %s", self.encoding) 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/kennethreitz/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): """Return content MIME type or empty string.""" self.content_type = httputil.get_content_type(self.headers) 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.proxy: kwargs["proxies"] = {self.proxytype: self.proxy} 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_info(_("Redirected to `%(url)s'.") % {'url': newurl}) # 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) 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_URL_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.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 = "Link: header %s" % 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 if self.content_type not in self.ContentMimetypes: log.debug( LOG_CHECK, "URL with content type %r is not parseable", self.content_type, ) return False return True 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.0.1/linkcheck/checker/ignoreurl.py000066400000000000000000000017261400504243600217760ustar00rootroot00000000000000# 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.0.1/linkcheck/checker/internpaturl.py000066400000000000000000000042361400504243600225160ustar00rootroot00000000000000# 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.0.1/linkcheck/checker/itmsservicesurl.py000066400000000000000000000026701400504243600232320ustar00rootroot00000000000000# 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.0.1/linkcheck/checker/mailtourl.py000066400000000000000000000320211400504243600217700ustar00rootroot00000000000000# 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("\\%s" % 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.query(domain, 'A') 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 = "%s:%s" % (self.scheme, emails) def can_get_content(self): """ mailto: URLs do not have any content @return: False @rtype: bool """ return False linkchecker-10.0.1/linkcheck/checker/nntpurl.py000066400000000000000000000070421400504243600214670ustar00rootroot00000000000000# 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 nntp: and news: links. """ import re import time import nntplib import random from . import urlbase from .. import log, LinkCheckerError, LOG_CHECK from .const import WARN_NNTP_NO_SERVER, WARN_NNTP_NO_NEWSGROUP random.seed() class NntpUrl(urlbase.UrlBase): """ Url link with NNTP scheme. """ def check_connection(self): """ Connect to NNTP server and try to request the URL article resource (if specified). """ nntpserver = self.host or self.aggregate.config["nntpserver"] if not nntpserver: self.add_warning( _("No NNTP server was specified, skipping this URL."), tag=WARN_NNTP_NO_SERVER, ) return nntp = self._connect_nntp(nntpserver) group = self.urlparts[2] while group[:1] == '/': group = group[1:] if '@' in group: # request article info (resp, number mid) number = nntp.stat("<" + group + ">")[1] self.add_info(_('Article number %(num)s found.') % {"num": number}) else: # split off trailing articel span group = group.split('/', 1)[0] if group: # request group info (resp, count, first, last, name) name = nntp.group(group)[4] self.add_info(_("News group %(name)s found.") % {"name": name}) else: # group name is the empty string self.add_warning( _("No newsgroup specified in NNTP URL."), tag=WARN_NNTP_NO_NEWSGROUP ) def _connect_nntp(self, nntpserver): """ This is done only once per checking task. Also, the newly introduced error codes 504 and 505 (both inclining "Too busy, retry later", are caught. """ tries = 0 nntp = None while tries < 2: tries += 1 try: nntp = nntplib.NNTP(nntpserver, usenetrc=False) except nntplib.NNTPTemporaryError: self.wait() except nntplib.NNTPPermanentError as msg: if re.compile("^50[45]").search(str(msg)): self.wait() else: raise if nntp is None: raise LinkCheckerError( _("NNTP server too busy; tried more than %d times.") % tries ) if log.is_debug(LOG_CHECK): nntp.set_debuglevel(1) self.add_info(nntp.getwelcome()) return nntp def wait(self): """Wait some time before trying to connect again.""" time.sleep(random.randrange(10, 30)) def can_get_content(self): """ NNTP urls have no content. @return: False @rtype: bool """ return False linkchecker-10.0.1/linkcheck/checker/proxysupport.py000066400000000000000000000070301400504243600226000ustar00rootroot00000000000000# 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. """ Mixin class for URLs that can be fetched over a proxy. """ import urllib.parse import urllib.request import os from .. import LinkCheckerError, log, LOG_CHECK, url as urlutil, httputil class ProxySupport: """Get support for proxying and for URLs with user:pass@host setting.""" def set_proxy(self, proxy): """Parse given proxy information and store parsed values. Note that only http:// proxies are supported, both for ftp:// and http:// URLs. """ self.proxy = proxy self.proxytype = "http" self.proxyauth = None if not self.proxy: return proxyurl = urllib.parse.urlparse(self.proxy) self.proxytype = proxyurl.scheme if self.proxytype not in ('http', 'https'): # Note that invalid proxies might raise TypeError in urllib2, # so make sure to stop checking at this point, not later. msg = _( "Proxy value `%(proxy)s' must start with 'http:' or 'https:'." ) % dict(proxy=proxy) raise LinkCheckerError(msg) if self.ignore_proxy_host(): # log proxy without auth info log.debug(LOG_CHECK, "ignoring proxy %r", self.proxy) self.add_info(_("Ignoring proxy setting `%(proxy)s'.") % dict(proxy=proxy)) self.proxy = None return log.debug(LOG_CHECK, "using proxy %r", self.proxy) self.add_info(_("Using proxy `%(proxy)s'.") % dict(proxy=self.proxy)) self.proxyhost = proxyurl.hostname self.proxyport = proxyurl.port if proxyurl.username is not None: username = proxyurl.username password = proxyurl.password if proxy.password is not None else "" auth = "%s:%s" % (username, password) self.proxyauth = "Basic " + httputil.encode_base64(auth) def ignore_proxy_host(self): """Check if self.host is in the $no_proxy ignore list.""" if urllib.request.proxy_bypass(self.host): return True no_proxy = os.environ.get("no_proxy") if no_proxy: entries = [urlutil.splitport(x.strip()) for x in no_proxy.split(",")] for host, port in entries: if host.lower() == self.host and port == self.port: return True return False def get_netloc(self): """Determine scheme, host and port for this connection taking proxy data into account. @return: tuple (scheme, host, port) @rtype: tuple(string, string, int) """ if self.proxy: scheme = self.proxytype host = self.proxyhost port = self.proxyport else: scheme = self.scheme host = self.host port = self.port return (scheme, host, port) linkchecker-10.0.1/linkcheck/checker/telneturl.py000066400000000000000000000051751400504243600220100ustar00rootroot00000000000000# 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 telnet: links. """ import telnetlib from . import urlbase from .. import log, LOG_CHECK def encode(s, encoding="iso-8859-1", errors="ignore"): """Encode telnet data like username and password.""" return s.encode(encoding, errors) class TelnetUrl(urlbase.UrlBase): """ Url link with telnet scheme. """ def build_url(self): """ Call super.build_url(), set default telnet port and initialize the login credentials. """ super().build_url() # default port if self.port is None: self.port = 23 # set user/pass self.user, self.password = self.get_user_password() def local_check(self): """ Warn about empty host names. Else call super.local_check(). """ if not self.host: self.set_result(_("Host is empty"), valid=False) return super().local_check() def check_connection(self): """ Open a telnet connection and try to login. Expected login label is "login: ", expected password label is "Password: ". """ self.url_connection = telnetlib.Telnet(timeout=self.aggregate.config["timeout"]) if log.is_debug(LOG_CHECK): self.url_connection.set_debuglevel(1) self.url_connection.open(self.host, self.port) if self.user: self.url_connection.read_until(b"login: ", 10) self.url_connection.write(encode(self.user) + b"\n") if self.password: self.url_connection.read_until(b"Password: ", 10) self.url_connection.write(encode(self.password) + b"\n") # XXX how to tell if we are logged in?? self.url_connection.write(b"exit\n") def can_get_content(self): """ Telnet URLs have no content. @return: False @rtype: bool """ return False linkchecker-10.0.1/linkcheck/checker/unknownurl.py000066400000000000000000000275151400504243600222160ustar00rootroot00000000000000# 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 [1] |coap\+ws # coap+ws [1] |coaps # coaps |coaps\+tcp # coaps+tcp [1] |coaps\+ws # coaps+ws [1] |crid # TV-Anytime Content Reference Identifier |data # data |dav # dav |dict # dictionary service protocol |dns # Domain Name System |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/]. |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 |mtqp # Message Tracking Query Protocol |mupdate # Mailbox Update (MUPDATE) Protocol |nfs # network file system protocol |ni # ni |nih # nih |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 |ark # ark |attachment # attachment |aw # aw |barion # barion |beshare # beshare |bitcoin # bitcoin |bitcoincash # bitcoincash |blob # blob |bolo # bolo |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 |conti # conti |cvs # cvs |dab # dab |dat # dat |diaspora # diaspora |did # did |dis # dis |dlna\-playcontainer # dlna-playcontainer |dlna\-playsingle # dlna-playsingle |dntp # dntp |doi # doi |dpp # dpp |drm # drm |drop # drop |dtmi # dtmi |dtn # DTNRG research and development |dvb # dvb |dweb # dweb |ed2k # ed2k |elsi # elsi |ethereum # ethereum |facetime # facetime |feed # feed |feedready # feedready |finger # finger |first\-run\-pen\-experience # first-run-pen-experience |fish # fish |fm # fm |fuchsia\-pkg # fuchsia-pkg |gg # gg |git # git |gizmoproject # gizmoproject |graph # graph |gtalk # gtalk |ham # ham |hcap # hcap |hcp # hcp |hxxp # hxxp |hxxps # hxxps |hydrazone # hydrazone |hyper # hyper |icon # icon |iotdisco # iotdisco |ipfs # ipfs |ipn # ipn |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 |lorawan # lorawan |lvlt # lvlt |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\-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\-lockscreencomponent\-config # ms-lockscreencomponent-config |ms\-media\-stream\-id # ms-media-stream-id |ms\-mixedrealitycapture # ms-mixedrealitycapture |ms\-mobileplans # ms-mobileplans |ms\-officeapp # ms-officeapp |ms\-people # ms-people |ms\-powerpoint # ms-powerpoint |ms\-project # ms-project |ms\-publisher # ms-publisher |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\-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 |notes # notes |ocf # ocf |oid # oid |onenote # onenote |onenote\-cmd # onenote-cmd |openpgp4fpr # openpgp4fpr |otpauth # otpauth |palm # palm |paparazzi # paparazzi |payment # payment |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 |secondlife # query |sftp # query |sgn # sgn |simpleledger # simpleledger |skype # skype |smb # smb |smtp # smtp |soldat # soldat |spiffe # spiffe |spotify # spotify |ssb # ssb |ssh # ssh |steam # steam |submit # submit |svn # svn |swh # swh |teamspeak # teamspeak |teliaeid # teliaeid |things # things |tool # tool |udp # udp |unreal # unreal |upt # upt |ut2004 # ut2004 |v\-event # v-event |ventrilo # ventrilo |view\-source # view-source |vscode # vscode |vscode\-insiders # vscode-insiders |vsls # vsls |webcal # webcal |wtai # wtai |wyciwyg # wyciwyg |xfire # xfire |xri # xri |ymsgr # ymsgr """ ignored_schemes_historical = r""" |fax # fax |filesystem # filesystem |mailserver # Access to data available from mail servers |modem # modem |pack # pack |prospero # Prospero Directory Service |snews # NNTP over SSL/TLS |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 |isbn # ISBN (int. book numbers) |javascript # JavaScript |slack # Slack Technologies client """ ignored_schemes = "^(%s%s%s%s)$" % ( 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.0.1/linkcheck/checker/urlbase.py000066400000000000000000001001561400504243600214220ustar00rootroot00000000000000# 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. """ import sys import os import urllib.parse from urllib.request import urlopen import time import errno import socket import select 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_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", "telnet") 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/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, ) 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 splitted 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 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 = [] 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 # 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_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 add_warning(self, s, tag=None): """ Add a warning string. """ item = (tag, s) if ( item not in self.warnings and tag not in self.aggregate.config["ignorewarnings"] ): 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 query and 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 = "%s:%d" % (self.host, self.port) if self.userinfo: urlparts[1] = "%s@%s" % (self.userinfo, host) else: urlparts[1] = host # safe 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 (socket.error, select.error): # 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 += ": %s" % 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 wether 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.encoding = self.soup.original_encoding or 'ISO-8859-1' log.debug(LOG_CHECK, "Content encoding %s", self.encoding) self.text = self.data.decode(self.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): """Add new URL to queue.""" if base: base_ref = urlutil.url_norm(base, encoding=self.encoding)[0] else: base_ref = None url_data = get_url_from( url, self.recursion_level + 1, self.aggregate, parent_url=self.url, base_ref=base_ref, line=line, column=column, page=page, name=name, parent_content_type=self.content_type, url_encoding=self.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 "<%s>" % 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 dictionnary wired_url_data''' for attr in urlDataAttr: setattr(self, attr, wired_url_data[attr]) linkchecker-10.0.1/linkcheck/cmdline.py000066400000000000000000000046251400504243600200000ustar00rootroot00000000000000# 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.0.1/linkcheck/colorama.py000066400000000000000000000117731400504243600201640ustar00rootroot00000000000000# 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, WindowsError): _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.0.1/linkcheck/configuration/000077500000000000000000000000001400504243600206535ustar00rootroot00000000000000linkchecker-10.0.1/linkcheck/configuration/__init__.py000066400000000000000000000556751400504243600230060ustar00rootroot00000000000000# 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. """ from functools import lru_cache import os import re import urllib.parse import urllib.request import shutil import socket import _LinkChecker_configdata as configdata from .. import log, LOG_CHECK, get_install_data, fileutil from . import confparse from xdg.BaseDirectory import xdg_config_home, xdg_data_home Version = configdata.version ReleaseDate = configdata.release_date AppName = configdata.name App = AppName + " " + Version Author = configdata.author HtmlAuthor = Author.replace(' ', ' ') Copyright = "Copyright (C) 2000-2016 Bastian Kleineidam, 2010-2021 " + Author HtmlCopyright = ("Copyright © 2000-2016 Bastian Kleineidam, 2010-2021 " + HtmlAuthor) HtmlAppInfo = App + ", " + HtmlCopyright Url = configdata.url SupportUrl = "https://github.com/linkchecker/linkchecker/issues" UserAgent = "Mozilla/5.0 (compatible; %s/%s; +%s)" % (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 `LICENSE' within this distribution.""" ) Portable = configdata.portable 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__"), ("xdg", "PyXDG", "__version__"), # optional modules ("argcomplete", "Argcomplete", None), ("GeoIP", "GeoIP", 'lib_version'), # on Unix systems ("pygeoip", "GeoIP", 'lib_version'), # on Windows systems ("sqlite3", "Pysqlite", 'version'), ("sqlite3", "Sqlite", 'sqlite_version'), ("gi", "PyGObject", '__version__'), ("meliae", "Meliae", '__version__'), ) def get_modules_info(): """Return unicode string with detected module info.""" module_infos = [] for (mod, name, version_attr) in Modules: if not fileutil.has_module(mod): continue if version_attr and hasattr(mod, version_attr): attr = getattr(mod, version_attr) version = attr() if callable(attr) else attr module_infos.append("%s %s" % (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_share_dir(): """Return absolute path of LinkChecker example configuration.""" return os.path.join(get_install_data(), "share", "linkchecker") def get_share_file(filename, devel_dir=None): """Return a filename in the share directory. @param devel_dir: directory to search when developing @type devel_dir: string @param filename: filename to search for @type filename: string @return: the found filename or None @rtype: string @raises: ValueError if not found """ paths = [get_share_dir()] if devel_dir is not None: # when developing paths.insert(0, devel_dir) for path in paths: fullpath = os.path.join(path, filename) if os.path.isfile(fullpath): return fullpath # not found msg = "%s not found in %s; check your installation" % (filename, paths) raise ValueError(msg) 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["nntpserver"] = os.environ.get("NNTP_SERVER", None) self["proxy"] = urllib.request.getproxies() self["sslverify"] = True self["threads"] = 10 self["timeout"] = 60 self["aborttimeout"] = 300 self["recursionlevel"] = -1 self["useragent"] = UserAgent # authentication self["authentication"] = [] self["loginurl"] = None self["loginuserfield"] = "login" self["loginpasswordfield"] = "password" self["loginextrafields"] = {} # filtering self["externlinks"] = [] self["ignorewarnings"] = [] 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 os.path.isfile(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_proxies() 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_proxies(self): """Try to read additional proxy settings which urllib does not support.""" if os.name != 'posix': return if "http" not in self["proxy"]: http_proxy = get_gnome_proxy() or get_kde_http_proxy() if http_proxy: self["proxy"]["http"] = http_proxy if "ftp" not in self["proxy"]: ftp_proxy = get_gnome_proxy(protocol="FTP") or get_kde_ftp_proxy() if ftp_proxy: self["proxy"]["ftp"] = ftp_proxy 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, then the own installed 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): try: self["sslverify"] = get_share_file('cacert.pem') except ValueError: pass def get_user_data(): """Get the user data folder. Returns "~/.linkchecker/" if this folder exists, \ "$XDG_DATA_HOME/linkchecker" if it does not. @rtype string """ homedotdir = normpath("~/.linkchecker/") userdata = ( homedotdir if os.path.isdir(homedotdir) else os.path.join(xdg_data_home, "linkchecker") ) return userdata def get_plugin_folders(): """Get linkchecker plugin folders. Default is "$XDG_DATA_HOME/linkchecker/plugins/". "~/.linkchecker/plugins/" is also supported for backwards compatibility, and is used if both directories exist.""" folders = [] defaultfolder = os.path.join(get_user_data(), "plugins") if not os.path.exists(defaultfolder) and not Portable: 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, but only if this is not a portable installation. Returns path to user config file (which might not exist due to copy failures or on portable systems). @return configuration filename @rtype string """ # initial config (with all options explained) initialconf = normpath(os.path.join(get_share_dir(), "linkcheckerrc")) # per user config settings homedotfile = normpath("~/.linkchecker/linkcheckerrc") userconf = ( homedotfile if os.path.isfile(homedotfile) else os.path.join(xdg_config_home, "linkchecker", "linkcheckerrc") ) if os.path.isfile(initialconf) and not os.path.exists(userconf) and not Portable: # 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 get_gnome_proxy(protocol="HTTP"): """Return host:port for a GNOME proxy if found, else None.""" try: import gi gi.require_version('Gio', '2.0') from gi.repository import Gio except ImportError: return None try: schema_id = "org.gnome.system.proxy.%s" % protocol.lower() # If the schema is not installed Gio.Settings.new() causes Trace/breakpoint trap source = Gio.SettingsSchemaSource.get_default() if source is None: log.debug(LOG_CHECK, "No GSettings schemas are installed") return None schema = source.lookup(schema_id, False) if schema is None: log.debug(LOG_CHECK, "%s not installed" % schema_id) return None settings = Gio.Settings.new(schema_id) if protocol == "HTTP" and not settings.get_boolean("enabled"): return None host = settings.get_string("host") port = settings.get_int("port") if host: if not port: port = 8080 return "%s:%d" % (host, port) except Exception as msg: log.debug(LOG_CHECK, "error getting %s proxy from GNOME: %s", (protocol, msg)) return None def get_kde_http_proxy(): """Return host:port for KDE HTTP proxy if found, else None.""" try: data = read_kioslaverc() return data.get("http_proxy") except Exception as msg: log.debug(LOG_CHECK, "error getting HTTP proxy from KDE: %s", msg) def get_kde_ftp_proxy(): """Return host:port for KDE HTTP proxy if found, else None.""" try: data = read_kioslaverc() return data.get("ftp_proxy") except Exception as msg: log.debug(LOG_CHECK, "error getting FTP proxy from KDE: %s", msg) # The following KDE functions are largely ported and ajusted from # Google Chromium: # http://src.chromium.org/viewvc/chrome/trunk/src/net/proxy/proxy_config_service_linux.cc?revision=HEAD&view=markup # Copyright (c) 2010 The Chromium Authors. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * 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. # * Neither the name of Google Inc. 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 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. def get_kde_config_dir(): """Return KDE configuration directory or None if not found.""" if os.environ.get("KDEHOME"): home = os.environ.get("KDEHOME") else: home = os.environ.get("HOME") if not home: log.debug(LOG_CHECK, "KDEHOME and HOME not set") return kde_config_dir = os.path.join(home, ".config") if not os.path.exists(kde_config_dir): kde_config_dir = os.path.join(home, ".kde4", "share", "config") if not os.path.exists(kde_config_dir): log.debug(LOG_CHECK, "%s does not exist" % kde_config_dir) return return kde_config_dir loc_ro = re.compile(r"\[.*\]$") @lru_cache(1) def read_kioslaverc(): """Read kioslaverc into data dictionary.""" data = {} kde_config_dir = get_kde_config_dir() if not kde_config_dir: return data in_proxy_settings = False filename = os.path.join(kde_config_dir, "kioslaverc") if not os.path.exists(filename): log.debug(LOG_CHECK, "%s does not exist" % filename) return data with open(filename) as fd: # First read all lines into dictionary since they can occur # in any order. for line in fd: line = line.rstrip() if line.startswith('['): in_proxy_settings = line.startswith("[Proxy Settings]") elif in_proxy_settings: if '=' not in line: continue key, value = line.split('=', 1) key = key.strip() value = value.strip() if not key: continue # trim optional localization key = loc_ro.sub("", key).strip() if not key: continue add_kde_setting(key, value, data) resolve_kde_settings(data) return data def add_kde_proxy(key, value, data): """Add a proxy value to data dictionary after sanity checks.""" if not value or value[:3] == "//:": return data[key] = value def add_kde_setting(key, value, data): """Add a KDE proxy setting value to data dictionary.""" if key == "ProxyType": mode = None int_value = int(value) if int_value == 1: mode = "manual" elif int_value == 2: # PAC URL mode = "pac" elif int_value == 3: # WPAD. mode = "wpad" elif int_value == 4: # Indirect manual via environment variables. mode = "indirect" data["mode"] = mode elif key == "Proxy Config Script": data["autoconfig_url"] = value elif key == "httpProxy": add_kde_proxy("http_proxy", value, data) elif key == "httpsProxy": add_kde_proxy("https_proxy", value, data) elif key == "ftpProxy": add_kde_proxy("ftp_proxy", value, data) elif key == "ReversedException": if value == "true": value = True elif value == "false": value = False else: value = int(value) != 0 data["reversed_bypass"] = value elif key == "NoProxyFor": data["ignore_hosts"] = split_hosts(value) elif key == "AuthMode": mode = int(value) # XXX todo def split_hosts(value): """Split comma-separated host list.""" return [host for host in value.split(", ") if host] def resolve_indirect(data, key, splithosts=False): """Replace name of environment variable with its value.""" value = data[key] env_value = os.environ.get(value) if env_value: if splithosts: data[key] = split_hosts(env_value) else: data[key] = env_value else: del data[key] def resolve_kde_settings(data): """Write final proxy configuration values in data dictionary.""" if "mode" not in data: return if data["mode"] == "indirect": for key in ("http_proxy", "https_proxy", "ftp_proxy"): if key in data: resolve_indirect(data, key) if "ignore_hosts" in data: resolve_indirect(data, "ignore_hosts", splithosts=True) elif data["mode"] != "manual": # unsupported config for key in ("http_proxy", "https_proxy", "ftp_proxy"): if key in data: del data[key] linkchecker-10.0.1/linkcheck/configuration/confparse.py000066400000000000000000000300471400504243600232110ustar00rootroot00000000000000# 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 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 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_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 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) 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, "nntpserver") self.read_string_option(section, "useragent") self.read_int_option(section, "maxrequestspersecond", min=1) 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) 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("entry/%s/%s" % (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, "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.0.1/linkcheck/containers.py000066400000000000000000000066051400504243600205320ustar00rootroot00000000000000# 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.0.1/linkcheck/cookies.py000066400000000000000000000043601400504243600200150ustar00rootroot00000000000000# 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 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))) 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.0.1/linkcheck/decorators.py000066400000000000000000000123571400504243600205330ustar00rootroot00000000000000# 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 aqcuired 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.0.1/linkcheck/director/000077500000000000000000000000001400504243600176175ustar00rootroot00000000000000linkchecker-10.0.1/linkcheck/director/__init__.py000066400000000000000000000110471400504243600217330ustar00rootroot00000000000000# 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 catched 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() return aggregator.Aggregate( config, _urlqueue, _robots_txt, plugin_manager, result_cache ) linkchecker-10.0.1/linkcheck/director/aggregator.py000066400000000000000000000213041400504243600223130ustar00rootroot00000000000000# 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"]: for cookie in from_file(config["cookiefile"]): session.cookies.set_cookie(cookie) return session class Aggregate: """Store thread-safe data collections for checker threads.""" 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.cookies = None requests_per_second = config["maxrequestspersecond"] self.wait_time_min = 1.0 / requests_per_second self.wait_time_max = max(self.wait_time_min + 0.5, 0.5) 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: proxy? 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() wait_time = random.uniform(self.wait_time_min, self.wait_time_max) self.times[host] = t + wait_time @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.getName().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: name = t.getName() if name.startswith("CheckThread-"): yield 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.0.1/linkcheck/director/checker.py000066400000000000000000000077301400504243600216040ustar00rootroot00000000000000# 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) # 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.getName() 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.0.1/linkcheck/director/console.py000066400000000000000000000123031400504243600216320ustar00rootroot00000000000000# 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("%s%s" % (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", "ftp_proxy", "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) print(_("Default locale:"), i18n.get_locale(), file=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.0.1/linkcheck/director/interrupter.py000066400000000000000000000034461400504243600225630ustar00rootroot00000000000000# 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.0.1/linkcheck/director/logger.py000066400000000000000000000051461400504243600214560ustar00rootroot00000000000000# 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.0.1/linkcheck/director/status.py000066400000000000000000000043111400504243600215130ustar00rootroot00000000000000# 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.0.1/linkcheck/director/task.py000066400000000000000000000035111400504243600211330ustar00rootroot00000000000000# 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.0.1/linkcheck/dummy.py000066400000000000000000000037021400504243600175130ustar00rootroot00000000000000# 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.0.1/linkcheck/fileutil.py000066400000000000000000000061361400504243600202010ustar00rootroot00000000000000# 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 os.error: return 0 def get_size(filename): """Return file size in Bytes, or -1 on error.""" try: return os.path.getsize(filename) except os.error: 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 a regular file and is readable.""" return os.path.isfile(filename) and os.access(filename, os.R_OK) def is_accessable_by_others(filename): """Check if file is group or world accessable.""" 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 linkchecker-10.0.1/linkcheck/ftpparse.py000066400000000000000000000123571400504243600202120ustar00rootroot00000000000000# 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 MSDOS: # "-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 # MSDOS 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.0.1/linkcheck/htmlutil/000077500000000000000000000000001400504243600176465ustar00rootroot00000000000000linkchecker-10.0.1/linkcheck/htmlutil/__init__.py000066400000000000000000000014021400504243600217540ustar00rootroot00000000000000# 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.0.1/linkcheck/htmlutil/htmlsoup.py000066400000000000000000000022721400504243600220760ustar00rootroot00000000000000# 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. """ from warnings import filterwarnings filterwarnings( "ignore", message="The soupsieve package is not installed. CSS selectors cannot be used.", category=UserWarning, module="bs4", ) from bs4 import BeautifulSoup def make_soup(markup, from_encoding=None): return BeautifulSoup( markup, "html.parser", from_encoding=from_encoding, multi_valued_attributes=None ) linkchecker-10.0.1/linkcheck/htmlutil/linkparse.py000066400000000000000000000205631400504243600222160ustar00rootroot00000000000000# 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 .. 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 attrs.get('rel') == 'dns-prefetch': 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' and not value.startswith('data:'): for img_candidate in value.split(','): try: url = img_candidate.split()[0] except IndexError: log.debug( LOG_CHECK, _("trailing comma in line: " "%(line)s srcset attribute: %(value)s") % {"line": lineno, "value": value} ) else: 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.0.1/linkcheck/htmlutil/loginformsearch.py000066400000000000000000000040421400504243600234020ustar00rootroot00000000000000# 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 "" % (self.url, self.data) 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.0.1/linkcheck/httputil.py000066400000000000000000000051701400504243600202360ustar00rootroot00000000000000# 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 base64 from datetime import datetime def encode_base64(s): """Encode given string in base64, excluding trailing newlines.""" return base64.b64encode(s) def x509_to_dict(x509): """Parse a x509 pyopenssl object to a dictionary with keys subject, subjectAltName and optional notAfter. """ from requests.packages.urllib3.contrib.pyopenssl import get_subj_alt_name res = { 'subject': ((('commonName', x509.get_subject().CN),),), 'subjectAltName': [('DNS', value) for value in get_subj_alt_name(x509)] } notAfter = x509.get_notAfter() if notAfter is not None: notAfter = notAfter.decode() parsedtime = asn1_generaltime_to_seconds(notAfter) if parsedtime is not None: res['notAfter'] = parsedtime.strftime('%b %d %H:%M:%S %Y') if parsedtime.tzinfo is None: res['notAfter'] += ' GMT' else: # give up parsing, just set the string res['notAfter'] = notAfter return res def asn1_generaltime_to_seconds(timestr): """The given string has one of the following formats YYYYMMDDhhmmssZ YYYYMMDDhhmmss+hhmm YYYYMMDDhhmmss-hhmm @return: a datetime object or None on error """ res = None timeformat = "%Y%m%d%H%M%S" try: res = datetime.strptime(timestr, timeformat + 'Z') except ValueError: try: res = datetime.strptime(timestr, timeformat + '%z') except ValueError: pass 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.0.1/linkcheck/i18n.py000066400000000000000000000140141400504243600171350ustar00rootroot00000000000000# 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 suppport import os import locale import gettext import sys import codecs # more supported languages are added in init() supported_languages = set(['en']) default_language = default_encoding = None default_directory = None default_domain = None def install_builtin(translator, do_unicode): """Install _() and _n() gettext methods into default namespace.""" import builtins builtins.__dict__['_'] = translator.gettext # also install ngettext builtins.__dict__['_n'] = translator.ngettext class Translator(gettext.GNUTranslations): """A translation class always installing its gettext methods into the default namespace.""" def install(self, do_unicode): """Install gettext methods into the default namespace.""" install_builtin(self, do_unicode) class NullTranslator(gettext.NullTranslations): """A dummy translation class always installing its gettext methods into the default namespace.""" def install(self, do_unicode): """Install gettext methods into the default namespace.""" install_builtin(self, do_unicode) def init(domain, directory, loc=None): """Initialize this gettext i18n module. Searches for supported languages and installs the gettext translator class.""" global default_language, default_encoding, default_domain, default_directory default_directory = directory default_domain = domain if os.path.isdir(directory): # get supported languages for lang in os.listdir(directory): path = os.path.join(directory, lang, 'LC_MESSAGES') mo_file = os.path.join(path, '%s.mo' % domain) if os.path.exists(mo_file): supported_languages.add(lang) if loc is None: loc, encoding = get_locale() else: encoding = get_locale()[1] if loc in supported_languages: default_language = loc else: default_language = "en" # Even if the default language is not supported, the encoding should # be installed. Otherwise the Python installation is borked. default_encoding = encoding install_language(default_language) def install_language(language): """Install translation service routines into default namespace.""" translator = get_translator( default_domain, default_directory, languages=[get_lang(language)], fallback=True ) do_unicode = True translator.install(do_unicode) def get_translator( domain, directory, languages=None, translatorklass=Translator, fallback=False, fallbackklass=NullTranslator, ): """Search the appropriate GNUTranslations class.""" translator = gettext.translation( domain, localedir=directory, languages=languages, class_=translatorklass, fallback=fallback, ) if not isinstance(translator, gettext.GNUTranslations) and fallbackklass: translator = fallbackklass() return translator def get_lang(lang): """Return lang if it is supported, or the default language.""" if lang in supported_languages: return lang return default_language def get_headers_lang(headers): """Return preferred supported language in given HTTP headers.""" if 'Accept-Language' not in headers: return default_language languages = headers['Accept-Language'].split(",") # sort with preference values pref_languages = [] for lang in languages: pref = 1.0 if ";" in lang: lang, _pref = lang.split(';', 1) try: pref = float(_pref) except ValueError: pass pref_languages.append((pref, lang)) pref_languages.sort() # search for lang for lang in (x[1] for x in pref_languages): if lang in supported_languages: return lang return default_language def get_locale(): """Search the default platform locale and norm it. @returns (locale, encoding) @rtype (string, string)""" try: loc, encoding = locale.getdefaultlocale() except ValueError: # locale configuration is broken - ignore that loc, encoding = None, None if loc is None: loc = "C" else: loc = norm_locale(loc) if encoding is None: encoding = "ascii" return (loc, encoding) def norm_locale(loc): """Normalize a locale.""" loc = locale.normalize(loc) # split up the locale into its base components pos = loc.find('@') if pos >= 0: loc = loc[:pos] pos = loc.find('.') if pos >= 0: loc = loc[:pos] pos = loc.find('_') if pos >= 0: loc = loc[:pos] return loc lang_names = { 'en': 'English', 'de': 'Deutsch', } lang_transis = { 'de': {'en': 'German'}, 'en': {'de': 'Englisch'}, } def lang_name(lang): """Return full name of given language.""" return lang_names[lang] def lang_trans(lang, curlang): """Return translated full name of given language.""" return lang_transis[lang][curlang] 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.0.1/linkcheck/lc_cgi.py000066400000000000000000000200601400504243600175740ustar00rootroot00000000000000# 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()) for output in checklink(form=form, env=environ): yield output _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 IOError("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.0.1/linkcheck/loader.py000066400000000000000000000102741400504243600176300ustar00rootroot00000000000000# 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 sys import zipfile import importlib from .fileutil import is_writable_by_others def is_frozen(): """Return True if running inside a py2exe- or py2app-generated executable.""" return hasattr(sys, "frozen") 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): """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 """ if is_frozen(): # find modules in library.zip filename zipname = os.path.dirname(os.path.dirname(__file__)) parentmodule = os.path.basename(os.path.dirname(__file__)) with zipfile.ZipFile(zipname, 'r') as f: prefix = "%s/%s/" % (parentmodule, packagename) modnames = [ os.path.splitext(n[len(prefix):])[0] for n in f.namelist() if n.startswith(prefix) and "__init__" not in n ] else: dirname = os.path.join(os.path.dirname(__file__), packagename) modnames = [x[:-3] for x in get_importable_files(dirname)] for modname in modnames: try: name = "..%s.%s" % (packagename, modname) yield importlib.import_module(name, __name__) except ImportError as msg: print("WARN: could not load module %s: %s" % (modname, 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: for plugin in get_module_plugins(module, classes): yield plugin 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.0.1/linkcheck/lock.py000066400000000000000000000047371400504243600173210ustar00rootroot00000000000000# 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.currentThread().getName() 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.currentThread().getName() 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.0.1/linkcheck/log.py000066400000000000000000000074541400504243600171510ustar00rootroot00000000000000# 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.0.1/linkcheck/logconf.py000066400000000000000000000057561400504243600200220ustar00rootroot00000000000000# 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.0.1/linkcheck/logger/000077500000000000000000000000001400504243600172635ustar00rootroot00000000000000linkchecker-10.0.1/linkcheck/logger/__init__.py000066400000000000000000000351031400504243600213760ustar00rootroot00000000000000# 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 IOError: 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 IOError: # ignore flush errors pass if self.close_fd: try: self.fd.close() except IOError: # 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 unitialized or closed file") else: try: self.fd.write(s, **args) except IOError: 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("%s%s" % (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( _("Get the newest version 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 (IOError, 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("%Y-%m-%d{0}%H:%M:%S.%fZ".format(sep)) return "" def _get_loggers(): """Return list of Logger classes.""" from .. import loader modules = loader.get_package_modules('logger') 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.0.1/linkcheck/logger/csvlog.py000066400000000000000000000113521400504243600211340ustar00rootroot00000000000000# 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.0.1/linkcheck/logger/customxml.py000066400000000000000000000073461400504243600217020ustar00rootroot00000000000000# 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.0.1/linkcheck/logger/dot.py000066400000000000000000000061071400504243600204270ustar00rootroot00000000000000# 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(' "%s" -> "%s" [' % (source, target)) self.writeln(' label="%s",' % dotquote(node["edge"])) if self.has_part("result"): self.writeln(" valid=%d," % 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.0.1/linkcheck/logger/failures.py000066400000000000000000000072631400504243600214570ustar00rootroot00000000000000# 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 linkcheck.configuration import get_user_data from . import _Logger from .. import log, LOG_CHECK 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): """Intialize 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, 'r', 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.0.1/linkcheck/logger/gml.py000066400000000000000000000054121400504243600204160ustar00rootroot00000000000000# 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.0.1/linkcheck/logger/graph.py000066400000000000000000000064001400504243600207360ustar00rootroot00000000000000# 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.0.1/linkcheck/logger/gxml.py000066400000000000000000000062651400504243600206150ustar00rootroot00000000000000# 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.0.1/linkcheck/logger/html.py000066400000000000000000000340511400504243600206040ustar00rootroot00000000000000# 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( _("Get the newest version 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.0.1/linkcheck/logger/none.py000066400000000000000000000023371400504243600206010ustar00rootroot00000000000000# 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.0.1/linkcheck/logger/sitemapxml.py000066400000000000000000000103641400504243600220240ustar00rootroot00000000000000# 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.0.1/linkcheck/logger/sql.py000066400000000000000000000103301400504243600204310ustar00rootroot00000000000000# 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.0.1/linkcheck/logger/text.py000066400000000000000000000303001400504243600206150ustar00rootroot00000000000000# 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, strformat, configuration, i18n 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", '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.output_encoding = args.get("encoding", i18n.default_encoding) self.init_fileoutput(args) self.colorparent = args.get('colorparent', 'default') self.colorurl = args.get('colorurl', 'default') self.colorname = args.get('colorname', 'default') self.colorreal = args.get('colorreal', 'default') self.colorbase = args.get('colorbase', 'default') self.colorvalid = args.get('colorvalid', 'default') self.colorinvalid = args.get('colorinvalid', 'default') self.colorinfo = args.get('colorinfo', 'default') self.colorwarning = args.get('colorwarning', 'default') self.colordltime = args.get('colordltime', 'default') self.colordlsize = args.get('colordlsize', 'default') self.colorreset = args.get('colorreset', 'default') 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( _("Get the newest version 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, 65), 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 = ["[%s] %s" % x for x in url_data.warnings] self.writeln(self.wrap(warning_msgs, 65), 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.0.1/linkcheck/logger/xmllog.py000066400000000000000000000063721400504243600211470ustar00rootroot00000000000000# 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(">%s" % (xmlquote(content), xmlquote(name))) linkchecker-10.0.1/linkcheck/memoryutil.py000066400000000000000000000031401400504243600205620ustar00rootroot00000000000000# 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.0.1/linkcheck/mimeutil.py000066400000000000000000000072161400504243600202110ustar00rootroot00000000000000# 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.0.1/linkcheck/plugins/parsepdf.py000066400000000000000000000062571400504243600216550ustar00rootroot00000000000000# 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.0.1/linkcheck/plugins/parseword.py000066400000000000000000000125151400504243600220510ustar00rootroot00000000000000# 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 (EnvironmentError, 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 pdfminer.""" 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(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.0.1/linkcheck/plugins/regexcheck.py000066400000000000000000000056241400504243600221560ustar00rootroot00000000000000# 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.0.1/linkcheck/plugins/sslcertcheck.py000066400000000000000000000111521400504243600225140ustar00rootroot00000000000000# 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 clamav configuration.""" 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 certficate "notAfter" value %r') % cert['notAfter'] url_data.add_warning(msg) return curTime = time.time() # Calculate seconds until certifcate expires. Can be negative if # the certificate is already expired. secondsValid = notAfter - curTime args = dict(expire=cert['notAfter']) if secondsValid < 0: msg = _('SSL certficate 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.0.1/linkcheck/plugins/syntaxchecks.py000066400000000000000000000127141400504243600225530ustar00rootroot00000000000000# 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 HTML pages 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.0.1/linkcheck/plugins/viruscheck.py000066400000000000000000000173141400504243600222130ustar00rootroot00000000000000# 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): """Try to ask GeoIP database for country info.""" 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 socket.error: 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 socket.error: 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 socket.error: 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 socket.error: sock.close() raise return sock def scan(data, clamconf): """Scan data for viruses. @return: (infection msgs, errors) @rtype: ([], []) """ try: scanner = ClamdScanner(clamconf) except socket.error: errmsg = _("Could not connect to ClamAV daemon.") return ([], [errmsg]) try: scanner.scan(data) finally: scanner.close() return scanner.infected, scanner.errors linkchecker-10.0.1/linkcheck/robotparser2.py000066400000000000000000000335011400504243600210040ustar00rootroot00000000000000# 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 http://www.robotstxt.org/wc/norobots-rfc.html """ 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, url='', session=None, proxies=None, auth=None, timeout=None): """Initialize internal entry lists and store given url and credentials.""" self.set_url(url) if session is None: self.session = requests.Session() else: self.session = session self.proxies = proxies 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.proxies: kwargs["proxies"] = self.proxies if self.timeout: kwargs["timeout"] = self.timeout try: response = self.session.get(self.url, **kwargs) response.raise_for_status() content_type = response.headers.get('content-type') self.encoding = response.encoding 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 acces 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.0.1/linkcheck/socketutil.py000066400000000000000000000040351400504243600205460ustar00rootroot00000000000000# 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 socket.error 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.0.1/linkcheck/strformat.py000066400000000000000000000174341400504243600204100ustar00rootroot00000000000000# 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 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 evaluting 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)s)(?:(?:%(sep)s)\s*)+" % {'sep': '\r'} _para_posix = r"(?:%(sep)s)(?:(?:%(sep)s)\s*)+" % {'sep': '\n'} _para_win = r"(?:%(sep)s)(?:(?:%(sep)s)\s*)+" % {'sep': '\r\n'} _para_ro = re.compile("%s|%s|%s" % (_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("%s%s" % (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, unit) % unit) time_str.reverse() if len(time_str) > 2: time_str.pop() return "%s%s" % (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.0.1/linkcheck/threader.py000066400000000000000000000024261400504243600201600ustar00rootroot00000000000000# 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.0.1/linkcheck/trace.py000066400000000000000000000055101400504243600174550ustar00rootroot00000000000000# 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.currentThread() tid = currentThread.ident tname = currentThread.getName() 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.0.1/linkcheck/url.py000066400000000000000000000371651400504243600171740ustar00rootroot00000000000000# 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 als # http://code.google.com/p/browsersec/wiki/Part1#Unicode_in_URLs url_encoding = "utf-8" default_ports = { 'http': 80, 'https': 443, 'nntps': 563, '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 _basic = { "_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 = ( r"([a-z0-9%(_path)s\+]|" r"(%%[%(_hex_safe)s][%(_hex_full)s]))" % _basic ) _safe_scheme_pattern = r"(https?|ftp)" _safe_domain_pattern = r"(%(_part)s(\.%(_part)s)*\.?)" % _basic _safe_host_pattern = _safe_domain_pattern + r"(:(80|8080|8000|443))?" % _basic _safe_path_pattern = ( r"((/([a-z0-9%(_path)s]|" r"(%%[%(_hex_safe)s][%(_hex_full)s]))+)*/?)" % _basic ) _safe_fragment_pattern = r"%s*" % _safe_char _safe_cgi = r"%s+(=(%s|/)+)?" % (_safe_char, _safe_char) _safe_query_pattern = r"(%s(&%s)*)?" % (_safe_cgi, _safe_cgi) _safe_param_pattern = r"(%s(;%s)*)?" % (_safe_cgi, _safe_cgi) safe_url_pattern = r"%s://%s%s(#%s)?" % ( _safe_scheme_pattern, _safe_host_pattern, _safe_path_pattern, _safe_fragment_pattern, ) is_safe_url = re.compile("(?i)^%s$" % safe_url_pattern).match is_safe_domain = re.compile("(?i)^%s$" % _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 splitted 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] = "%s%s" % ( 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 = "%s:%d" % (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("%s=%s%s" % (k, v, sep)) elif v is None: f.append("%s%s" % (k, sep)) else: # some sites do not work when the equal sign is missing f.append("%s=%s" % (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("%s=%s%s" % (k, v, sep)) else: f.append("%s%s" % (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 "%s?%s" % (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(r"^[%s]*$" % _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.0.1/linkchecker000077500000000000000000000606301400504243600162660ustar00rootroot00000000000000#!/usr/bin/python3 -u # 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 sys import codecs import os import pprint import argparse import getpass # installs _() and _n() gettext functions into global namespace import linkcheck from linkcheck import log, logconf LOG_CMDLINE = linkcheck.LOG_CMDLINE logconf.init_log_config() # override argparse gettext method with the one from linkcheck.init_i18n() # argparse._ = _ # now import the rest of the linkchecker gang from linkcheck.cmdline import ( print_version, print_usage, aggregate_url, LCArgumentParser, print_plugins, ) import linkcheck.checker import linkcheck.configuration import linkcheck.fileutil import linkcheck.logger import linkcheck.ansicolor from linkcheck.director import console, check_urls, get_aggregate from linkcheck.strformat import stripurl # optional modules has_argcomplete = linkcheck.fileutil.has_module("argcomplete") has_profile = linkcheck.fileutil.has_module("yappi") has_meliae = linkcheck.fileutil.has_module("meliae") # default profiling filename _profile = "linkchecker.prof" _username = None _password = None # 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. o When checking 'news:' links the given NNTP host doesn't need to be the same as the host of the user browsing your pages. """ ) ProxySupport = _( """PROXY SUPPORT To use a proxy on Unix or Windows set $http_proxy, $https_proxy or $ftp_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, and GNOME or KDE on Linux 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 ~/.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( [ " o %s - %s" % (tag, desc) for tag, desc in sorted(linkcheck.checker.const.Warnings.items()) ] ) ) Epilog = "\n".join( ( Examples, LoggerTypes, RegularExpressions, CookieFormat, ProxySupport, Notes, Retval, Warnings, ) ) def has_encoding(encoding): """Detect if Python can encode in a certain encoding.""" try: codecs.lookup(encoding) return True except LookupError: return False # instantiate option parser and configure options argparser = LCArgumentParser( epilog=Epilog, formatter_class=argparse.RawDescriptionHelpFormatter ) # build a config object for this check session config = linkcheck.configuration.Configuration() config.set_status_logger(console.StatusLogger()) # ================== general options ===================== group = argparser.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" "~/.linkchecker/linkcheckerrc (under Windows\n" "%%HOMEPATH%%\\.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 = argparser.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, $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": linkcheck.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": linkcheck.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 = argparser.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( "-N", "--nntp-server", dest="nntpserver", metavar="STRING", help=_( "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." ), ) group.add_argument( "-p", "--password", action="store_false", dest="password", default=False, 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. The default\n" "timeout is %d seconds." ) % config["timeout"], ) 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." ), ) argparser.add_argument("url", nargs="*") # ================= auto completion ===================== if has_argcomplete: import argcomplete argcomplete.autocomplete(argparser) 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 # read and parse command line options and arguments options = argparser.parse_args() # initialize 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) 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 = linkcheck.configuration.normpath(options.configfile) if os.path.isfile(path): files.append(path) else: log.warn(LOG_CMDLINE, _("Unreadable config file: %r"), options.configfile) config.read(files=files) except linkcheck.LinkCheckerError as msg: # config error print_usage(str(msg)) linkcheck.drop_privileges() # 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 do_profile = False if options.version: print_version() if not options.warnings: config["warnings"] = options.warnings if options.externstrict: pats = [linkcheck.get_link_pat(arg, strict=True) for arg in options.externstrict] config["externlinks"].extend(pats) if options.extern: pats = [linkcheck.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, linkcheck.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 linkcheck.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 linkcheck.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'", } ) logger = config.logger_new(ftype, **ns) config["fileoutput"].append(logger) if options.nntpserver: config["nntpserver"] = options.nntpserver 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(console.encode(msg)) constructauth = True if options.profile: do_profile = options.profile 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 options.cookiefile is not None: config["cookiefile"] = options.cookiefile 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 linkcheck.fileutil.is_readable(options.cookiefile): config["cookiefile"] = options.cookiefile else: msg = _("Could not read cookie file %s") % options.cookiefile log.error(LOG_CMDLINE, msg) # 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 import linkcheck.trace linkcheck.trace.trace_filter([r"^linkcheck"]) 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 if do_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) else: log.warn( LOG_CMDLINE, _( "The `yappi' Python module is not installed," " therefore the --profile option is disabled." ), ) do_profile = False # 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"]: import linkcheck.memoryutil if has_meliae: log.info(LOG_CMDLINE, _("Dumping memory statistics...")) filename = linkcheck.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, linkcheck.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.0.1/po/000077500000000000000000000000001400504243600144675ustar00rootroot00000000000000linkchecker-10.0.1/po/Makefile000066400000000000000000000016101400504243600161250ustar00rootroot00000000000000XGETTEXT := xgettext MSGFMT := msgfmt MSGMERGE := msgmerge POSOURCES = $(shell find ../linkcheck -name \*.py) \ ../linkchecker $(shell python3 -c 'import argparse; print(argparse.__file__)') LDIR = ../share/locale PACKAGE = linkchecker TEMPLATE = $(PACKAGE).pot MYMAIL := bastian.kleineidam@web.de LFILE = LC_MESSAGES/$(PACKAGE).mo # defined language (add new languages here) LANGUAGES = de fr es MOFILES = $(wildcard *.mo) all: $(MOFILES) %.mo: %.po $(MSGFMT) -c --statistics -o $@ $< %.po: $(TEMPLATE) $(MSGMERGE) -U --suffix=.bak $@ $< template: $(TEMPLATE) $(TEMPLATE): $(POSOURCES) $(XGETTEXT) -w 80 --default-domain=$(PACKAGE) --language=Python \ --copyright-holder="Bastian Kleineidam <$(MYMAIL)>" \ --msgid-bugs-address=$(MYMAIL) -o $(TEMPLATE) \ --keyword=_n:1,2 $(POSOURCES) clean: @for f in $(LANGUAGES); do rm -f $(LDIR)/$$f/$(LFILE); done rm -f *.mo *.bak .PHONY: clean linkchecker-10.0.1/po/de.mo000066400000000000000000001003311400504243600154120ustar00rootroot00000000000000% pq'!D 5BQp"":%=c l"v)#! * 4r>z ,7%H&n#<0`%aZt}#6Y/Hx#!6!$ "?2"r"x""""!"# #%#%9#2_###!*$L$1i$$7$ $$a%t%#y%.%%%/%9&0Y&&L&?&='?['W' '9'J9('(/(.(, )8)/A)q)u,|,,%,,0, -#+-3O--j--.N0 0&0&2<>2"{2E223Py44<t555*55E6*K6*v666V6/74778X9 m9 x9+9 9 99&90:"6:Y:w::,:u:1L;*~;;;);$<34<Eh<<<c=,g==*=(="= ">)/>3Y>A>@>>?O?j?????"???'?2&@&Y@H@@@ AA.AJA^AgA|A?AA4A1,BU^BBB"B3 C.AC*pCCC9C/C5-D cDnD DDDDDD)sF9F"FFJG _GmG%|GG;GGH)HIH;ZHdH J K0K:CK ~K&KKKFK3OKX'XHXX$Y('YPYoY6YYYY.YE$ZjZ~Z)[$G[;l[[Y[\4\hO\\'\3\] ]7?]@w]9]]\]PU^O^R^rI__A_b`+j`6`5` a $a>.ama|dd$d+d#d4d&2e-Ye:eeeTfdfdi i>i+j:j#2kUVk.klLmmYn oo:.oioaro-o/pO2pVpppqr\s rs |s)ss s s8s9)tct'ttt.t|u2u6u5u5,v1bv<v>vw/ww7wx?/x=ox3x x0x5yFUy@yVy%4zZzvz~zzz.z)zz1 {/<{/l{S{"{ | 4|@|!_|| ||$|E|(}<G};}]}~<~+Z~K~5~4!=_By8< 2!> `j&ĀAVm f"UCb ux+;In![/ZSM^6sO<]qPea2z>`K4#~=kv?&}g|Y:d( wD8QoJTH{cX- \yR0WGNh7_t%*)Er@j,5pBLl'F.31i9$ (%d duplicates not printed) (%d ignored or duplicates not printed)%(prefix)s%(duration).02f seconds%(scheme)s URL ignored.%(w3type)s validation error at line %(line)s col %(column)s: %(msg)s%.3f seconds%d day%d days%d error found%d errors found%d hour%d hours%d link checked.%d links checked.%d minute%d minutes%d second%d seconds%d warning found%d warnings found%d year%d years******** LinkChecker internal error, over and out ****************** 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 ;) . , col %d, line %dAdded trailing slash to directory.An error occurred while storing a cookie.Anchor `%(name)s' not found.Article number %(num)s found.Available anchors: %(anchors)s.BaseCOOKIE 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" CRITICALCache keyCanceled.Check but do not recurse into URLs matching the given regular expression. This option can be given multiple times.Check recursively all links up to given depth. A negative depth will enable infinite recursion. Default depth is infinite.Check timeChecking optionsConfiguration file %r does not exist.Configuration file %r is not readable.Content size is zero.Content types: %(image)d image, %(text)d text, %(video)d video, %(audio)d audio, %(application)d application, %(mail)d mail and %(other)d other.Could not connect to ClamAV daemon.Could not get current working directory: %(msg)sCould not get the content of the URL.Could not import %(module)s for %(feature)s. Install %(module)s from %(url)s to use this feature.Could not start a new thread. Check that the current user is allowed to start new threads.D/L timeDEBUGDefault locale:Do not print check status messages.Domain part of mail address `%(addr)s' has invalid IP.Domain part of mail address `%(addr)s' too long. Allowed 255 chars, was %(length)d chars.Don't log warnings. Default is to log warnings.Dumping memory statistics...ERROREXAMPLES 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 Effective URL %(url)r.Enter LinkChecker HTTP/FTP password for user %(user)s:Enter LinkChecker HTTP/FTP password:Enter LinkChecker password for user %(user)s at %(strpattern)s:ErrorError parsing CGI values: %sError parsing configuration: %sError using login URL: %(msg)s.Error: %(msg)sExecute '%(program)s -h' for helpExternFTP file size too largeFile size too largeFor example execute 'chmod go-rw %s'.Found %(match)r at line %(line)d in link contents.General optionsGenerate no more than the given number of threads. Default number of threads is 10. To disable threading specify a non-positive number.Get the newest version at %(url)sGet the newest version at %sGot invalid DNS answer %(answer)s for %(domain)s.Got no answer from FTP serverHappy birthday for LinkChecker, I'm %d years old today!Host is emptyHostname not foundIGNORE WARNINGS The following warnings are recognized in the 'ignorewarnings' config file entry: INFOIgnoring proxy setting `%(proxy)s'.Illegal argument %(arg)r for option %(option)sInfoInvalid debug level %(level)rInvalid domain part of mail address `%(addr)s'.Invalid top level domain part of mail address `%(addr)s'.Leading or trailing whitespace in URL `%(url)s'.LevelLocal part of mail address `%(addr)s' contains unquoted character `%(char)s.Local part of mail address `%(addr)s' may not contain two dots.Local part of mail address `%(addr)s' may not end with a dot.Local part of mail address `%(addr)s' may not start with a dot.Local part of mail address `%(addr)s' too long. Allowed 64 chars, was %(length)d chars.Local time:Log all URLs. Default is to log only errors and warnings.Mail address `%(addr)s' too long. Allowed 256 chars, was %(length)d chars.Missing `@' in mail address `%(addr)s'.Missing domain part of mail address `%(addr)s'.Missing local part of mail address `%(addr)s'.Missing trailing directory slash in ftp url.ModifiedNNTP server too busy; tried more than %d times.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. o When checking 'news:' links the given NNTP host doesn't need to be the same as the host of the user browsing your pages. NOTSETNameNews group %(name)s found.No MX mail host for %(domain)s found.No NNTP server was found.No NNTP server was specified, skipping this URL.No host for %(domain)s found.No newsgroup specified in NNTP URL.No statistics available since no URLs were checked.OKOnly check syntax of URLs matching the given regular expression. This option can be given multiple times.Output optionsOutput 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 http://docs.python.org/lib/standard-encodings.html. 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 %(loggertypes)s. You can specify this option multiple times to output to more than one file. Default is no file output. Note that you can suppress all console output with the option '-o none'.Overwrite profiling file %(file)r? Press Ctrl-C to cancel, RETURN to continue.Parent URLPrint debugging output for the given logger. Available loggers are %(lognamelist)s. 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.Print version and exit.Proxy value `%(proxy)s' must start with 'http:' or 'https:'.Python %(version)s on %(platform)sQuiet operation, an alias for '-o none'. This is only useful with -F.REGULAR EXPRESSIONS Only Python regular expressions are accepted by LinkChecker. See http://www.amk.ca/python/howto/regex/ for an introduction in regular expressions. The only addition is that a leading exclamation mark negates the regular expression. 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 Read a file with initial cookie data. The cookie data format is explained below.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 -u.Read list of white-space separated URLs to check from stdin.Real URLRedirected to `%(url)s'.Remote host has closed connection: %(msg)sResultRunning as root user; dropping privileges by changing user to nobody.Running with python -O disables debugging.ScannerDaemonOutputFormat must be disabledSee %(url)s for more info on setting file permissions.Set the timeout for connection attempts in seconds. The default timeout is %d seconds.SizeSpecify an NNTP server for 'news:...' links. Default is the environment variable NNTP_SERVER. If no host is given, only the syntax of the link is checked.Specify output as %(loggertypes)s. Default output type is text. The ENCODING specifies the output encoding, the default is that of your locale. Valid encodings are listed at http://docs.python.org/lib/standard-encodings.html.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.Start checking at %sStatisticsStatistics:Stopped checking at %(time)s (%(duration)s)System info:That's it.The IP is obfuscated.The NNTP newsgroup could not be found.The URL contains leading or trailing whitespace.The URL content size is too large.The URL content size is zero.The URL had no content.The URL has been ignored.The URL is longer than the recommended size.The URL path %(path)r is not the same as the system path %(realpath)r. You should always use the system path in URLs.The effective URL is different from the original.The file: URL is missing a trailing slash.The file: path is not the same as the system specific path.The ftp: URL is missing a trailing slash.The mail MX host could not be found.The memory dump has been written to `%(filename)s'.There was %(num)d internal error.There were %(num)d internal errors.These URLs are still active: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 -p.URLURL %(url)s has obfuscated IP address %(ip)sURL has empty hostnameURL has unparsable domain name: %(domain)sURL has unparsable domain name: %(name)sURL host %(host)r has invalid portURL is emptyURL is unrecognized or has invalid syntaxURL lengths: min=%(min)d, max=%(max)d, avg=%(avg)d.Unknown encoding %(encoding)r in %(output)r for option %(option)sUnknown logger type %(type)r in %(output)r for option %(option)sUnquoted double quote or backslash in mail address `%(addr)s'.Unreadable config file: %rUsing proxy `%(proxy)s'.ValidWARNWARNINGWarningWrite comments and bugs to %(url)sWrite comments and bugs to %sactivating text logger output.another interrupt will exit immediatelycertificate did not include "notAfter" informationclamd is not ready for stream scanningcould not copy initial configuration file %(src)r to %(dst)r: %(errmsg)rcould not get content: %(msg)screated by %(app)s at %(time)sdirectorydisabling login URL %(url)s.disallowed url %r was givenempty url was givenfilteredinvalid %s option %rinvalid empty value for %s: %s invalid login URL `%s'. Only HTTP and HTTPS URLs are supported.invalid recursion level %rinvalid value for %s: %d must not be greater than %dinvalid value for %s: %d must not be less than %dlocal files are only checked without parent URL or when the parent URL is also a filelogin URL is incomplete.login URL is not a HTTP URL.missing auth part in entry %(val)rmissing user or URL pattern in authentication data.no CGI password fieldname given for login URL.no CGI user fieldname given for login URL.no files or URLs givenno url was givenno user/password authentication data found for login URL.one of TCPSocket or LocalSocket must be enabledonly one of TCPSocket and LocalSocket must be enabledruntime %sshow this help message and exitsyntax OKunsupported language %ruser abort; force shutdownvalid CSS syntaxvalid HTML syntaxProject-Id-Version: $Id$ Report-Msgid-Bugs-To: bastian.kleineidam@web.de PO-Revision-Date: 2020-06-19 16:42+0100 Last-Translator: Bastian Kleineidam Language-Team: de Language: de MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1); X-Generator: Gtranslator 3.36.0 (%d doppelte Vorkommen nicht ausgegeben) (%d ignorierte oder doppelte Vorkommen nicht ausgegeben)%(prefix)s%(duration).02f Sekunden%(scheme)s URL ignoriert.%(w3type)s Validierungsfehler in Zeile %(line)s Spalte %(column)s: %(msg)s%.3f Sekunden%d Tag%d Tage%d Fehler gefunden%d Fehler gefunden%d Stunde%d Stunden%d Verknüpfung überprüft.%d Verknüpfungen überprüft.%d Minute%d Minuten%d Sekunde%d Sekunden%d Warnung gefunden%d Warnungen gefunden%d Jahr%d Jahre******** LinkChecker interner Fehler, und tschüß ****************** Hoppla. ************* Sie haben einen internen Fehler in LinkChecker entdeckt. Bitte schreiben Sie einen Fehlerbericht an %s mit den folgenden Informationen: - die URL oder Datei, welche Sie gerade prüfen - die untenstehenden Systeminformationen. Bei Benutzung des Kommandozeilenprogramms: - ihre Kommandozeilenargumente und/oder Ihre Konfiguration. - die Ausgabe eines Debuglaufs mit Option "-Dall" Wenn Sie Informationen aus privaten Gründen unterlassen, ist das in Ordnung. Ich werde trotzdem versuchen, Ihnen zu helfen. Sie müssen mir allerdings irgendwas geben, womit ich arbeiten kann ;). , Spalte %d, Zeile %dSchrägstrich wurde zu Verzeichnis hinzugefügt.Ein Fehler trat auf während des Speicherns eines Cookies.Anker `%(name)s' nicht gefunden.Artikel Nummer %(num)s wurde gefunden.Verfügbare Anker: %(anchors)s.BasisCOOKIE-DATEIEN Eine Cookie-Datei enthält Standard RFC 805 Kopfdaten mit den folgenden möglichen Namen: Scheme (optional) Setzt das Schema für das die Cookies gültig sind; Standardschema ist 'http'. Host (erforderlich) Setzt die Domäne für die die Cookies gültig sind. Path (optional) Gibt den Pfad für den die Cookies gültig sind; Standardpfad ist '/'. Set-cookie (optional) Setzt den Cookie Name/Wert. Kann mehrmals angegeben werden. Mehrere Einträge können 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.com' beginnen: Host: example.org Path: /hello Set-cookie: ID="smee" Set-cookie: spam="egg" Scheme: https Host: example.com Set-cookie: baggage="elitist"; comment="hologram" KRITISCHCache SchlüsselAbgebrochen.Prüfe URLs die auf den angegebenen regulären Ausdruck zutreffen, aber steige nicht rekursiv in sie hinab. Diese Option kann mehrmals angegeben werden.Prüfe rekursiv alle Verknüpfungen bis zu der angegebenen Tiefe. Eine negative Tiefe erwirkt unendliche Rekursion. Standard Tiefe ist unendlich.PrüfzeitPrüf-OptionenKonfigurationsdatei %r existiert nicht.Konfigurationsdatei %r ist nicht lesbar.Größe des Inhalts ist Null.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.Konnte nicht zu ClamAV verbinden.Konnte aktuelles Arbeitsverzeichnis nicht ermitteln: %(msg)sKonnte den Inhalt der URL nicht bekommen.Konnte Modul %(module)s für %(feature)s nicht importieren. Installieren Sie %(module)s von %(url)s, um dieses Feature zu nutzen.Konnte keinen neuen Thread starten. Überprüfen sie, ob der aktuelle Benutzer neue Threads starten darf.D/L ZeitDEBUGStandard Locale:Gebe keine Statusmeldungen aus.Domänen-Teil der E-Mail-Adresse `%(addr)s' besitzt eine ungültige IP-Adresse.Domänen-Teil der E-Mail-Adresse `%(addr)s' ist zu lang. Erlaubt sind 255 Zeichen, es waren aber %(length)d Zeichen.Gebe keine Warnungen aus. Standard ist die Ausgabe von Warnungen.Generiere Speicherabzug...FEHLERBEISPIELE Der häufigste Gebrauch prüft die angegebene Domäne rekursiv, inklusive aller einzelnen URLs die außerhalb dieser Domäne zeigen: linkchecker http://www.example.de/ Beachten Sie, dass diese Prüfung die komplette Website abprüft, welche mehrere Hunderttausend URLs besitzen kann. Benutzen Sie die Option -r, um die Rekursionstiefe einzuschränken. Keine Verbindung zu mailto: Rechner aufbauen, prüfe lediglich deren URL Syntax. Alle anderen Links werden wie üblich geprüft: linkchecker --ignore-url=^mailto: www.example.org Prüfe eine lokale HTML Datei unter UNIX: linkchecker ../bla.html subdir/blubber.html Prüfe eine lokale HTML Datei unter Windows: linkchecker c:\temp\test.html Sie können den "http://" Teil der URL weglassen wenn die Domäne mit "www." beginnt: linkchecker www.example.de Sie können den "ftp://" Teil der URL weglassen wenn die Domäne mit "ftp." beginnt: linkchecker -r0 ftp.example.org Effektive URL %(url)r.Gebe LinkChecker HTTP/FTP Passwort für Benutzer %(user)s ein:Gebe LinkChecker HTTP/FTP Passwort ein:Gebe LinkChecker Passwort für Benutzer %(user)s bei %(strpattern)s ein:FehlerFehler beim Parsen der CGI-Werte: %sFehler beim Parsen der Konfiguration: %sFehler bei Login URL: %(msg)s.Fehler: %(msg)sFühren Sie '%(program)s -h' aus, um Hilfe zu erhaltenExternFTP Dateigröße ist zu großDateigröße ist zu großFühren Sie zum Beispiel 'chmod go-rw %s' aus.Habe %(match)r in Zeile %(line)d im Inhalt der Verknüpfung gefunden.Allgemeine OptionenGeneriere nicht mehr als die angegebene Anzahl von Threads. Standard Anzahl von Threads ist 10. Geben Sie eine negative Zahl an, um Threading zu deaktivieren.Die neueste Version gibt es unter %(url)sDie neueste Version gibt es unter %sUngültige DNS Antwort %(answer)s für %(domain)s erhalten.Keine Antwort vom FTP ServerHerzlichen Glückwunsch zum Geburtstag, LinkChecker, ich bin heute %d Jahre alt geworden!Rechnername ist leerRechnername nicht gefundenWARNUNGEN IGNORIEREN Die folgenden Warnungen werden vom Konfigurationseintrag 'ignorewarnings' erkannt: INFOIgnoriere Proxy Einstellung `%(proxy)s'Ungültiges Argument %(arg)r für Option %(option)sInfoUngültiger Debuglevel %(level)rUngültige Domänen-Teil der E-Mail-Adresse `%(addr)s'.Ungültige Toplevel-Domänen-Teil der E-Mail-Adresse `%(addr)s'.Die URL %(url)s enthält Leerzeichen am Anfang oder Ende.TiefeLokaler Teil der E-Mail-Adresse `%(addr)s' beinhaltet ein nicht kodiertes Zeichen `%(char)s.Der lokale Teil der E-Mail-Adresse `%(addr)s' darf nicht zwei Punkte beinhalten.Der lokale Teil der E-Mail-Adresse `%(addr)s' darf nicht mit einem Punkt enden.Der lokale Teil der E-Mail-Adresse `%(addr)s' darf nicht mit einem Punkt beginnen.Lokaler Teil der E-Mail-Adresse `%(addr)s' ist zu lang. Erlaubt sind 64 Zeichen, es waren aber %(length)d Zeichen.Uhrzeit:Logge alle URLs. Standard ist es, nur fehlerhafte URLs zu loggen.E-Mail-Adresse `%(addr)s' ist zu lang. Erlaubt sind 256 Zeichen, es waren aber %(length)d Zeichen.Fehlendes `@' in E-Mail-Adresse `%(addr)s'.Fehlender Domänen-Teil der E-Mail-Adresse `%(addr)s'.Fehlender lokaler Teil der E-Mail-Adresse `%(addr)s'.Fehlender / am Ende der FTP url.GeändertNNTP Server zu beschäftigt; habe es mehr als %d mal versucht.KOMMENTARE o 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 als Argumente angeben. o 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 Optionen -s und -i um dies zu verhindern. o Javascript Links werden zur Zeit ignoriert. o Wenn Ihr System keine Threads unterstützt deaktiviert LinkChecker diese automatisch. o Sie können mehrere Benutzer/Passwort Paare in einer Konfigurationsdatei angeben. o Beim Prüfen von 'news:' Links muss der angegebene NNTP Rechner nicht unbedingt derselbe wie der des Benutzers sein. NICHTSNameNachrichtengruppe %(name)s gefunden.Kein MX mail host für %(domain)s gefunden.Es wurde kein NNTP Server gefunden.Kein NNTP Server angegeben; prüfe lediglich Syntax.Kein Rechner für %(domain)s gefunden.Keine Newsgroup in der NNTP URL spezifiziert.Keine Statistik verfügbar, da keine URLs geprüft wurden.OKPrüfe lediglich den Syntax der URLs, welche auf den angegebenen regulären Ausdruck zutreffen. Diese Option kann mehrmals angegebenen werden.AusgabeoptionenAusgabe in eine Datei namens linkchecker-out.TYPE, $HOME/.linkchecker/blacklist bei 'blacklist' Ausgabe, oder FILENAME falls angegeben. Das ENCODING gibt die Ausgabeenkodierung an, der Standard ist die Enkodierung der ausgewählten Spracheinstellung. Gültige Enkodierungen sind unter http://docs.python.org/lib/standard-encodings.html aufgeführt. Der FILENAME und ENCODING Teil wird bei dem Ausgabetyp 'none' ignoriert, ansonsten wird die Datei überschreiben falls sie existiert. Sie können diese Option mehr als einmal verwenden. Gültige Ausgabetypen sind %(loggertypes)s. Standard ist keine Dateiausgabe. Beachten Sie dass die Option '-o none' jegliche Ausgaben auf der Konsole verhindert.Profildatei %(file)r überschreiben? Drücken Sie Strg-C zum Abbrechen, EINGABETASTE zum Fortfahren.Vater URLGebe Debugmeldungen aus für den angegebenen Logger. Verfügbare Logger sind %(lognamelist)s. 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 debuggen. Für exakte Resultate wird Threading während Debugläufen deaktiviert.Drucke die Version und beende das Programm.Proxy `%(proxy)s' muss mit 'http:' oder 'https:' beginnen.Python %(version)s auf %(platform)sKeine Ausgabe, ein Alias für '-o none'. Dies ist nur in Verbindung mit -F nützlich.REGULÄRE AUSDRÜCKE Lediglich Pythons reguläre Ausdrücke werden von LinkChecker akzeptiert. Siehe http://www.amk.ca/python/howto/regex/ für eine Einführung in reguläre Ausdrücke. Die einzige Hinzufügung ist, dass ein regulärer Ausdruck negiert wird falls er mit einem Ausrufezeichen beginnt. RÜCKGABEWERT Der Rückgabewert ist nicht Null falls o ungültige Verknüpfungen gefunden wurden oder o Warnungen gefunden wurden und Warnungen aktiviert sind o ein Programmfehler aufgetreten ist Lese eine Datei mit Cookie-Daten. Das Datenformat ist weiter unten erklärt.Lese ein Passwort von der Kommandozeile und verwende es für HTTP und FTP Authorisation. Für FTP ist das Standardpasswort 'anonymous@'. Für HTTP gibt es kein Standardpasswort. Siehe auch -u.Lese eine Liste von URLs zum Prüfen von der Standardeingabe, getrennt durch Leerzeichen.Tats. URLZu `%(url)s' umgeleitet.Entfernter Rechner hat die Verbindung geschlossen: %(msg)sErgebnisLaufe als Benutzer root; Privilegien werden aufgegeben indem auf Benutzer nobody gewechselt wird.Die Option python -O verhindert das Debuggen.ScannerDaemonOutputFormat muss deaktiviert seinSiehe %(url)s für mehr Informationen über das Setzen von Dateiberechtigungen.Setze den Timeout für Verbindungen in Sekunden. Der Standard Timeout ist %d Sekunden.GrößeGibt ein NNTP Rechner für 'news:...' Links. Standard ist die Umgebungsvariable NNTP_SERVER. Falls kein Rechner angegeben ist, wird lediglich auf korrekte Syntax des Links geprüft.Spezifiziere die Ausgabe als %(loggertypes)s. Standardausgabe ist text. Das ENCODING gibt die Ausgabeenkodierung an, der Standard ist die Enkodierung der ausgewählten Spracheinstellung. Gültige Enkodierungen sind unter http://docs.python.org/lib/standard-encodings.html aufgeführt.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.Beginne Prüfen am %sStatistikStatistik:Beende Prüfen am %(time)s (%(duration)s)Systeminformation:Das war's.Die IP-Adresse ist verschleiert.Die NNTP Nachrichtengruppe konnte nicht gefunden werden.Die URL %(url)s enthält Leerzeichen am Anfang oder Ende.Der URL Inhalt ist zu groß.Der URL Inhaltsgrößenangabe ist Null.Die URL besitzt keinen Inhalt.Die URL wurde ignoriert.Die URL ist länger als die empfohlene Länge.Der URL Pfad %(path)r ist nicht derselbe wie der Systempfad %(realpath)r. Sie sollten immer den Systempfad in URLs benutzen.Die effektive URL unterscheidet sich vom Original.Der file: URL fehlt ein abschließender Schrägstrich.Der file: Pfad ist nicht derselbe wie der Systempfad.Der ftp: URL fehlt ein abschließender Schrägstrich.Der MX Mail-Rechner konnte nicht gefunden werden.Der Speicherabzug wurde in Datei `%(filename)s' geschrieben.Es gab %(num)d internen Fehler.Es gab %(num)d interne Fehler.Folgende URLs sind noch aktiv:Verwende den angegebenen Benutzernamen für HTTP und FTP Authorisation. Für FTP ist der Standardname 'anonymous'. Für HTTP gibt es kein Standardnamen. Siehe auch -p.URLURL %(url)s besitzt die verschleierte IP-Adresse %(ip)sURL hat leeren RechnernamenURL besitzt einen nicht analysierbaren Rechnernamen: %(domain)sURL besitzt einen nicht analysierbaren Rechnernamen: %(name)sURL Rechner %(host)r hat eine ungültige PortnummerURL ist leerURL ist unbekannt oder besitzt ungültige SyntaxURL Längen: min=%(min)d, max=%(max)d, mittel=%(avg)dUnbekanntes Encoding %(encoding)r in %(output)r für Option %(option)sUnbekannter Logtyp %(type)r in %(output)r für Option %(option)sNicht kodiertes doppeltes Anführungszeichen oder Escape in E-Mail-Adresse `%(addr)s'.Nicht lesbare Konfigurationsdatei: %rVerwende Proxy `%(proxy)s'.GültigWARNWARNUNGWarnungSchreiben Sie Kommentare und Fehler an %(url)sSchreiben Sie Kommentare und Fehler an %saktiviere Loggerausgabe text.ein weiter Abbruch beendet dieses Programm sofortZertifikat besitzt keine "notAfter"-Informationclamd ist nicht bereit, einen Stream zu prüfenKonnte initiale Konfigurationsdatei %(src)r nicht nach %(dst)r kopieren: %(errmsg)rkonnte Inhalt nicht lesen: %(msg)serstellt von %(app)s am %(time)sVerzeichnisdeaktiviere Login URL %(url)s.ungültige URL %r wurde angegebenleere URL wurde angegebengefiltertungültige %s Option %rungültiger leerer Wert für %s: %s ungültige Login URL `%s'. Nur HTTP und HTTPS URLs sind unterstützt.ungültiger Rekursionslevel %rungültiger Wert für %s: %d darf nicht größer als %d seinungültiger Wert für %s: %d darf nicht kleiner als %d seinlokale Dateien werden nur ohne Vater-URL geprüft oder wenn die Vater-URL auch eine Datei istLogin URL ist unvollständig.Login URL ist keine HTTP URL.fehlende Authentifizierung in entry %(val)rFehlender Benutzer oder regulärer URL Ausdruck in Authentifizierungsdaten. kein CGI Passwort Feldname für Login URL angegeben.kein CGI Benutzer Feldname für Login URL angegeben.keine Dateien oder URLs angegebenkeine URL wurde angegebenkeine Benutzer/Passwort-Authentifizierung für Login URL gefunden.einer von TCPSocket oder LocalSocket muss aktiviert seinnur einer von TCPSocket oder LocalSocket muss aktiviert seinLaufzeit %sZeige diesen Hilfetext und beendeSyntax OKnicht unterstützte Sprache %rBenutzerabbruch; erzwinge Programmendegültige CSS Syntaxgültige HTML Syntaxlinkchecker-10.0.1/po/de.po000066400000000000000000001662341400504243600154330ustar00rootroot00000000000000# German translation for LinkChecker. # Bastian Kleineidam , 2009-2011. # msgid "" msgstr "" "Project-Id-Version: $Id$\n" "Report-Msgid-Bugs-To: bastian.kleineidam@web.de\n" "POT-Creation-Date: 2020-06-19 16:25+0100\n" "PO-Revision-Date: 2020-06-19 16:42+0100\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 3.36.0\n" #: ../linkcheck/configuration/confparse.py:62 #, python-format msgid "Error parsing configuration: %s" msgstr "Fehler beim Parsen der Konfiguration: %s" #: ../linkcheck/configuration/confparse.py:69 #, python-format msgid "invalid empty value for %s: %s\n" msgstr "ungültiger leerer Wert für %s: %s\n" #: ../linkcheck/configuration/confparse.py:83 #: ../linkcheck/plugins/sslcertcheck.py:108 #, 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/configuration/confparse.py:86 #, 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:175 #, python-format msgid "missing auth part in entry %(val)r" msgstr "fehlende Authentifizierung in entry %(val)r" #: ../linkcheck/configuration/confparse.py:181 #, 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:206 #, 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:251 #, 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/configuration/__init__.py:242 #, python-format msgid "Configuration file %r does not exist." msgstr "Konfigurationsdatei %r existiert nicht." #: ../linkcheck/configuration/__init__.py:244 #, python-format msgid "Configuration file %r is not readable." msgstr "Konfigurationsdatei %r ist nicht lesbar." #: ../linkcheck/configuration/__init__.py:254 msgid "missing user or URL pattern in authentication data." msgstr "" "Fehlender Benutzer oder regulärer URL Ausdruck in Authentifizierungsdaten." #: ../linkcheck/configuration/__init__.py:293 msgid "activating text logger output." msgstr "aktiviere Loggerausgabe text." #: ../linkcheck/configuration/__init__.py:303 msgid "no CGI password fieldname given for login URL." msgstr " kein CGI Passwort Feldname für Login URL angegeben." #: ../linkcheck/configuration/__init__.py:307 msgid "no CGI user fieldname given for login URL." msgstr "kein CGI Benutzer Feldname für Login URL angegeben." #: ../linkcheck/configuration/__init__.py:311 msgid "no user/password authentication data found for login URL." msgstr "keine Benutzer/Passwort-Authentifizierung für Login URL gefunden." #: ../linkcheck/configuration/__init__.py:314 msgid "login URL is not a HTTP URL." msgstr "Login URL ist keine HTTP URL." #: ../linkcheck/configuration/__init__.py:318 msgid "login URL is incomplete." msgstr "Login URL ist unvollständig." #: ../linkcheck/configuration/__init__.py:322 #, python-format msgid "disabling login URL %(url)s." msgstr "deaktiviere Login URL %(url)s." #: ../linkcheck/configuration/__init__.py:384 #, 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:425 #, 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/lc_cgi.py:207 #, python-format msgid "unsupported language %r" msgstr "nicht unterstützte Sprache %r" #: ../linkcheck/lc_cgi.py:212 msgid "empty url was given" msgstr "leere URL wurde angegeben" #: ../linkcheck/lc_cgi.py:214 #, python-format msgid "disallowed url %r was given" msgstr "ungültige URL %r wurde angegeben" #: ../linkcheck/lc_cgi.py:216 msgid "no url was given" msgstr "keine URL wurde angegeben" #: ../linkcheck/lc_cgi.py:221 #, python-format msgid "invalid recursion level %r" msgstr "ungültiger Rekursionslevel %r" #: ../linkcheck/lc_cgi.py:227 #, python-format msgid "invalid %s option %r" msgstr "ungültige %s Option %r" #: ../linkcheck/lc_cgi.py:251 #, 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" "\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/__init__.py:117 msgid "CRITICAL" msgstr "KRITISCH" #: ../linkcheck/__init__.py:118 msgid "ERROR" msgstr "FEHLER" #: ../linkcheck/__init__.py:119 msgid "WARN" msgstr "WARN" #: ../linkcheck/__init__.py:120 msgid "WARNING" msgstr "WARNUNG" #: ../linkcheck/__init__.py:121 msgid "INFO" msgstr "INFO" #: ../linkcheck/__init__.py:122 msgid "DEBUG" msgstr "DEBUG" #: ../linkcheck/__init__.py:123 msgid "NOTSET" msgstr "NICHTS" #: ../linkcheck/__init__.py:135 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/cmdline.py:59 #, python-format msgid "Error: %(msg)s" msgstr "Fehler: %(msg)s" #: ../linkcheck/cmdline.py:60 #, python-format msgid "Execute '%(program)s -h' for help" msgstr "Führen Sie '%(program)s -h' aus, um Hilfe zu erhalten" #: ../linkcheck/strformat.py:247 #, python-format msgid "%(prefix)s%(duration).02f seconds" msgstr "%(prefix)s%(duration).02f Sekunden" #: ../linkcheck/strformat.py:250 #, python-format msgid "%d second" msgid_plural "%d seconds" msgstr[0] "%d Sekunde" msgstr[1] "%d Sekunden" #: ../linkcheck/strformat.py:251 #, python-format msgid "%d minute" msgid_plural "%d minutes" msgstr[0] "%d Minute" msgstr[1] "%d Minuten" #: ../linkcheck/strformat.py:252 #, python-format msgid "%d hour" msgid_plural "%d hours" msgstr[0] "%d Stunde" msgstr[1] "%d Stunden" #: ../linkcheck/strformat.py:253 #, python-format msgid "%d day" msgid_plural "%d days" msgstr[0] "%d Tag" msgstr[1] "%d Tage" #: ../linkcheck/strformat.py:254 #, python-format msgid "%d year" msgid_plural "%d years" msgstr[0] "%d Jahr" msgstr[1] "%d Jahre" #: ../linkcheck/strformat.py:323 #, 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/director/aggregator.py:160 msgid "These URLs are still active:" msgstr "Folgende URLs sind noch aktiv:" #: ../linkcheck/director/aggregator.py:167 #, python-format msgid "" "%(num)d URLs are still active. After a timeout of %(timeout)s the active " "URLs will stop." msgstr "" #: ../linkcheck/director/__init__.py:35 #, python-format msgid "Error using login URL: %(msg)s." msgstr "Fehler bei Login URL: %(msg)s." #: ../linkcheck/director/__init__.py:41 #, fuzzy, python-format msgid "Error starting log output: %(msg)s." msgstr "Fehler bei Login URL: %(msg)s." #: ../linkcheck/director/__init__.py:56 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:88 #, fuzzy msgid "interrupt; waiting for active threads to finish" msgstr "Benutzerabbruch; warte auf Beendigung von aktiven Verbindungen" #: ../linkcheck/director/__init__.py:90 msgid "another interrupt will exit immediately" msgstr "ein weiter Abbruch beendet dieses Programm sofort" #: ../linkcheck/director/__init__.py:106 msgid "user abort; force shutdown" msgstr "Benutzerabbruch; erzwinge Programmende" #: ../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:41 #, 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:43 #, fuzzy, python-format msgid "%4d link" msgid_plural "%4d links" msgstr[0] "geprüfte Verknüpfung" msgstr[1] "geprüfte Verknüpfung" #: ../linkcheck/director/console.py:45 #, python-format msgid "%3d URL" msgid_plural "%3d URLs" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:47 #, python-format msgid "runtime %s" msgstr "Laufzeit %s" #: ../linkcheck/director/console.py:67 #, 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:114 msgid "Default locale:" msgstr "Standard Locale:" #: ../linkcheck/director/console.py:136 msgid "System info:" msgstr "Systeminformation:" #: ../linkcheck/director/console.py:138 msgid "Released on:" msgstr "" #: ../linkcheck/director/console.py:139 ../linkchecker:404 #, python-format msgid "Python %(version)s on %(platform)s" msgstr "Python %(version)s auf %(platform)s" #: ../linkcheck/director/console.py:145 msgid "Local time:" msgstr "Uhrzeit:" #: ../linkcheck/director/console.py:146 msgid "sys.argv:" msgstr "" #: ../linkcheck/director/console.py:151 msgid "released" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:68 msgid "valid HTML syntax" msgstr "gültige HTML Syntax" #: ../linkcheck/plugins/syntaxchecks.py:74 #, fuzzy, python-format msgid "HTML syntax check plugin error: %(msg)s " msgstr "tidy HTML Parser verursachte Fehler: %(msg)s" #: ../linkcheck/plugins/syntaxchecks.py:105 msgid "valid CSS syntax" msgstr "gültige CSS Syntax" #: ../linkcheck/plugins/syntaxchecks.py:111 #, fuzzy, python-format msgid "CSS syntax check plugin error: %(msg)s " msgstr "Syntaxfehler in %(arg)r: %(msg)s" #: ../linkcheck/plugins/syntaxchecks.py:119 #, 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/sslcertcheck.py:63 msgid "certificate did not include \"notAfter\" information" msgstr "Zertifikat besitzt keine \"notAfter\"-Information" #: ../linkcheck/plugins/sslcertcheck.py:66 msgid "SSL verification is disabled; enable the sslverify option" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:77 #, fuzzy, python-format msgid "Invalid SSL certficate \"notAfter\" value %r" msgstr "ungültiger \"notAfter\" Zertifikatwert %r" #: ../linkcheck/plugins/sslcertcheck.py:86 #, fuzzy, python-format msgid "SSL certficate is expired on %(expire)s." msgstr "Zertifikat ist am %s abgelaufen" #: ../linkcheck/plugins/sslcertcheck.py:91 #, python-format msgid "SSL certificate expires on %(expire)s and is only %(valid)s valid." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:94 #, python-format msgid "SSL certificate expires on %(expire)s and is %(valid)s valid." msgstr "" #: ../linkcheck/plugins/anchorcheck.py:59 #, python-format msgid "Anchor `%(name)s' not found." msgstr "Anker `%(name)s' nicht gefunden." #: ../linkcheck/plugins/anchorcheck.py:60 #, python-format msgid "Available anchors: %(anchors)s." msgstr "Verfügbare Anker: %(anchors)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:162 msgid "only one of TCPSocket and LocalSocket must be enabled" msgstr "nur einer von TCPSocket oder LocalSocket muss aktiviert sein" #: ../linkcheck/plugins/viruscheck.py:191 msgid "one of TCPSocket or LocalSocket must be enabled" msgstr "einer von TCPSocket oder LocalSocket muss aktiviert sein" #: ../linkcheck/plugins/viruscheck.py:226 msgid "Could not connect to ClamAV daemon." msgstr "Konnte nicht zu ClamAV verbinden." #: ../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/locationinfo.py:46 #, fuzzy, python-format msgid "URL is located in %(location)s." msgstr "URL befindet sich in %(country)s." #: ../linkcheck/checker/fileurl.py:118 #, python-format msgid "Could not get current working directory: %(msg)s" msgstr "Konnte aktuelles Arbeitsverzeichnis nicht ermitteln: %(msg)s" #: ../linkcheck/checker/fileurl.py:152 msgid "Added trailing slash to directory." msgstr "Schrägstrich wurde zu Verzeichnis hinzugefügt." #: ../linkcheck/checker/fileurl.py:174 msgid "" "local files are only checked without parent URL or when the parent URL is " "also a file" msgstr "" "lokale Dateien werden nur ohne Vater-URL geprüft oder wenn die Vater-URL " "auch eine Datei ist" #: ../linkcheck/checker/fileurl.py:177 msgid "directory" msgstr "Verzeichnis" #: ../linkcheck/checker/fileurl.py:194 #, 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/ftpurl.py:91 msgid "Got no answer from FTP server" msgstr "Keine Antwort vom FTP Server" #: ../linkcheck/checker/ftpurl.py:94 #, python-format msgid "Remote host has closed connection: %(msg)s" msgstr "Entfernter Rechner hat die Verbindung geschlossen: %(msg)s" #: ../linkcheck/checker/ftpurl.py:140 msgid "Missing trailing directory slash in ftp url." msgstr "Fehlender / am Ende der FTP url." #: ../linkcheck/checker/ftpurl.py:201 msgid "FTP file size too large" msgstr "FTP Dateigröße ist zu groß" #: ../linkcheck/checker/mailtourl.py:84 #, 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:125 #, python-format msgid "Error parsing CGI values: %s" msgstr "Fehler beim Parsen der CGI-Werte: %s" #: ../linkcheck/checker/mailtourl.py:148 #, 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:152 #, python-format msgid "Missing `@' in mail address `%(addr)s'." msgstr "Fehlendes `@' in E-Mail-Adresse `%(addr)s'." #: ../linkcheck/checker/mailtourl.py:158 #, 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:162 #, 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:166 #, 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:170 #, 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:179 #, 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:184 #, 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:188 #, 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:192 #, 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:197 #, 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:209 #, 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:215 #, 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:219 #, 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:252 #, 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:260 #, python-format msgid "No host for %(domain)s found." msgstr "Kein Rechner für %(domain)s gefunden." #: ../linkcheck/checker/mailtourl.py:274 #, 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:286 #, fuzzy msgid "Valid mail address syntax" msgstr "Ungültige Mail Syntax" #: ../linkcheck/checker/unknownurl.py:31 #, python-format msgid "%(scheme)s URL ignored." msgstr "%(scheme)s URL ignoriert." #: ../linkcheck/checker/unknownurl.py:33 #, fuzzy msgid "ignored" msgstr "%s URL ignoriert." #: ../linkcheck/checker/unknownurl.py:35 msgid "URL is unrecognized or has invalid syntax" msgstr "URL ist unbekannt oder besitzt ungültige Syntax" #: ../linkcheck/checker/const.py:102 msgid "The effective URL is different from the original." msgstr "Die effektive URL unterscheidet sich vom Original." #: ../linkcheck/checker/const.py:104 msgid "Could not get the content of the URL." msgstr "Konnte den Inhalt der URL nicht bekommen." #: ../linkcheck/checker/const.py:105 msgid "The URL content size is too large." msgstr "Der URL Inhalt ist zu groß." #: ../linkcheck/checker/const.py:106 msgid "The URL content size is zero." msgstr "Der URL Inhaltsgrößenangabe ist Null." #: ../linkcheck/checker/const.py:107 msgid "The URL is longer than the recommended size." msgstr "Die URL ist länger als die empfohlene Länge." #: ../linkcheck/checker/const.py:108 msgid "The URL contains leading or trailing whitespace." msgstr "Die URL %(url)s enthält Leerzeichen am Anfang oder Ende." #: ../linkcheck/checker/const.py:109 msgid "The file: URL is missing a trailing slash." msgstr "Der file: URL fehlt ein abschließender Schrägstrich." #: ../linkcheck/checker/const.py:111 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: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:115 msgid "An error occurred while storing a cookie." msgstr "Ein Fehler trat auf während des Speicherns eines Cookies." #: ../linkcheck/checker/const.py:116 msgid "The URL has been ignored." msgstr "Die URL wurde ignoriert." #: ../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 "No NNTP server was found." msgstr "Es wurde kein NNTP Server gefunden." #: ../linkcheck/checker/const.py:119 msgid "The NNTP newsgroup could not be found." msgstr "Die NNTP Nachrichtengruppe konnte nicht gefunden werden." #: ../linkcheck/checker/const.py:120 msgid "The IP is obfuscated." msgstr "Die IP-Adresse ist verschleiert." #: ../linkcheck/checker/const.py:121 #, fuzzy msgid "XML could not be parsed." msgstr "Der MX Mail-Rechner konnte nicht gefunden werden." #: ../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/checker/nntpurl.py:44 msgid "No NNTP server was specified, skipping this URL." msgstr "Kein NNTP Server angegeben; prüfe lediglich Syntax." #: ../linkcheck/checker/nntpurl.py:54 #, python-format msgid "Article number %(num)s found." msgstr "Artikel Nummer %(num)s wurde gefunden." #: ../linkcheck/checker/nntpurl.py:61 #, python-format msgid "News group %(name)s found." msgstr "Nachrichtengruppe %(name)s gefunden." #: ../linkcheck/checker/nntpurl.py:64 msgid "No newsgroup specified in NNTP URL." msgstr "Keine Newsgroup in der NNTP URL spezifiziert." #: ../linkcheck/checker/nntpurl.py:88 #, 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." #: ../linkcheck/checker/urlbase.py:65 #, python-format msgid "URL has unparsable domain name: %(name)s" msgstr "URL besitzt einen nicht analysierbaren Rechnernamen: %(name)s" #: ../linkcheck/checker/urlbase.py:124 #, 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:127 msgid "filtered" msgstr "gefiltert" #: ../linkcheck/checker/urlbase.py:162 #, 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:324 msgid "URL is empty" msgstr "URL ist leer" #: ../linkcheck/checker/urlbase.py:338 #, python-format msgid "Effective URL %(url)r." msgstr "Effektive URL %(url)r." #: ../linkcheck/checker/urlbase.py:344 #, fuzzy, python-format msgid "URL length %(len)d is longer than %(max)d." msgstr "URL-Länge %(len)d ist länger als %(warn)d." #: ../linkcheck/checker/urlbase.py:390 #, python-format msgid "URL host %(host)r has invalid port" msgstr "URL Rechner %(host)r hat eine ungültige Portnummer" #: ../linkcheck/checker/urlbase.py:397 msgid "URL has empty hostname" msgstr "URL hat leeren Rechnernamen" #: ../linkcheck/checker/urlbase.py:421 #, 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:456 msgid "Hostname not found" msgstr "Rechnername nicht gefunden" #: ../linkcheck/checker/urlbase.py:459 #, fuzzy, python-format msgid "Bad hostname %(host)r: %(msg)s" msgstr "konnte Rechnernamen %(host)r nicht parsen: %(msg)s" #: ../linkcheck/checker/urlbase.py:475 #, python-format msgid "could not get content: %(msg)s" msgstr "konnte Inhalt nicht lesen: %(msg)s" #: ../linkcheck/checker/urlbase.py:526 #, fuzzy, python-format msgid "Content size %(size)s is larger than %(maxbytes)s." msgstr "Inhalt %(dlsize)s is größer als %(maxbytes)s." #: ../linkcheck/checker/urlbase.py:619 msgid "Content size is zero." msgstr "Größe des Inhalts ist Null." #: ../linkcheck/checker/urlbase.py:649 ../linkcheck/checker/httpurl.py:313 msgid "File size too large" msgstr "Dateigröße ist zu groß" #: ../linkcheck/checker/urlbase.py:717 #, python-format msgid "URL has unparsable domain name: %(domain)s" msgstr "URL besitzt einen nicht analysierbaren Rechnernamen: %(domain)s" #: ../linkcheck/checker/proxysupport.py:43 #, python-format msgid "Proxy value `%(proxy)s' must start with 'http:' or 'https:'." msgstr "Proxy `%(proxy)s' muss mit 'http:' oder 'https:' beginnen." #: ../linkcheck/checker/proxysupport.py:49 #, python-format msgid "Ignoring proxy setting `%(proxy)s'." msgstr "Ignoriere Proxy Einstellung `%(proxy)s'" #: ../linkcheck/checker/proxysupport.py:54 #, python-format msgid "Using proxy `%(proxy)s'." msgstr "Verwende Proxy `%(proxy)s'." #: ../linkcheck/checker/itmsservicesurl.py:32 msgid "Missing required url parameter" msgstr "" #: ../linkcheck/checker/telneturl.py:52 msgid "Host is empty" msgstr "Rechnername ist leer" #: ../linkcheck/checker/httpurl.py:125 #, 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:126 msgid "syntax OK" msgstr "Syntax OK" #: ../linkcheck/checker/httpurl.py:257 #, python-format msgid "Redirected to `%(url)s'." msgstr "Zu `%(url)s' umgeleitet." #: ../linkcheck/checker/httpurl.py:297 msgid "OK" msgstr "OK" #: ../linkcheck/logger/text.py:98 ../linkcheck/logger/__init__.py:380 #, python-format msgid "Get the newest version at %(url)s" msgstr "Die neueste Version gibt es unter %(url)s" #: ../linkcheck/logger/text.py:100 ../linkcheck/logger/__init__.py:382 #, python-format msgid "Write comments and bugs to %(url)s" msgstr "Schreiben Sie Kommentare und Fehler an %(url)s" #: ../linkcheck/logger/text.py:104 ../linkcheck/logger/html.py:122 #, python-format msgid "Start checking at %s" msgstr "Beginne Prüfen am %s" #: ../linkcheck/logger/text.py:158 ../linkcheck/logger/html.py:192 #, python-format msgid ", line %d" msgstr ", Zeile %d" #: ../linkcheck/logger/text.py:160 ../linkcheck/logger/html.py:194 #, python-format msgid ", col %d" msgstr ", Spalte %d" #: ../linkcheck/logger/text.py:162 ../linkcheck/logger/html.py:196 #, fuzzy, python-format msgid ", page %d" msgstr ", Zeile %d" #: ../linkcheck/logger/text.py:178 ../linkcheck/logger/text.py:190 #: ../linkcheck/logger/html.py:220 ../linkcheck/logger/html.py:232 #, python-format msgid "%.3f seconds" msgstr "%.3f Sekunden" #: ../linkcheck/logger/text.py:214 ../linkcheck/logger/html.py:261 msgid "Valid" msgstr "Gültig" #: ../linkcheck/logger/text.py:217 ../linkcheck/logger/html.py:266 msgid "Error" msgstr "Fehler" #: ../linkcheck/logger/text.py:226 msgid "The check has been interrupted; results are not complete." msgstr "" #: ../linkcheck/logger/text.py:227 ../linkcheck/logger/html.py:291 msgid "That's it." msgstr "Das war's." #: ../linkcheck/logger/text.py:228 #, fuzzy, python-format msgid "%d link" msgid_plural "%d links" msgstr[0] "geprüfte Verknüpfung" msgstr[1] "geprüfte Verknüpfung" #: ../linkcheck/logger/text.py:232 #, 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:235 ../linkcheck/logger/html.py:296 #, python-format msgid "%d warning found" msgid_plural "%d warnings found" msgstr[0] "%d Warnung gefunden" msgstr[1] "%d Warnungen gefunden" #: ../linkcheck/logger/text.py:243 ../linkcheck/logger/html.py:299 #, python-format msgid " (%d ignored or duplicates not printed)" msgstr " (%d ignorierte oder doppelte Vorkommen nicht ausgegeben)" #: ../linkcheck/logger/text.py:246 ../linkcheck/logger/html.py:302 #, python-format msgid "%d error found" msgid_plural "%d errors found" msgstr[0] "%d Fehler gefunden" msgstr[1] "%d Fehler gefunden" #: ../linkcheck/logger/text.py:254 ../linkcheck/logger/html.py:305 #, python-format msgid " (%d duplicates not printed)" msgstr " (%d doppelte Vorkommen nicht ausgegeben)" #: ../linkcheck/logger/text.py:259 ../linkcheck/logger/html.py:311 #, 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/text.py:263 ../linkcheck/logger/__init__.py:390 #: ../linkcheck/logger/html.py:316 #, python-format msgid "Stopped checking at %(time)s (%(duration)s)" msgstr "Beende Prüfen am %(time)s (%(duration)s)" #: ../linkcheck/logger/text.py:270 msgid "Statistics:" msgstr "Statistik:" #: ../linkcheck/logger/text.py:272 #, fuzzy, python-format msgid "Downloaded: %s." msgstr "Heruntergeladen: %s" #: ../linkcheck/logger/text.py:275 ../linkcheck/logger/html.py:276 #, 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/text.py:278 ../linkcheck/logger/html.py:280 #, 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/text.py:283 ../linkcheck/logger/html.py:285 msgid "No statistics available since no URLs were checked." msgstr "Keine Statistik verfügbar, da keine URLs geprüft wurden." #: ../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 "Vater 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:278 #, 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:377 #, python-format msgid "created by %(app)s at %(time)s" msgstr "erstellt von %(app)s am %(time)s" #: ../linkcheck/logger/html.py:273 msgid "Statistics" msgstr "Statistik" #: ../linkcheck/logger/html.py:293 #, 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:321 #, python-format msgid "Get the newest version at %s" msgstr "Die neueste Version gibt es unter %s" #: ../linkcheck/logger/html.py:324 #, python-format msgid "Write comments and bugs to %s" msgstr "Schreiben Sie Kommentare und Fehler an %s" #: ../linkchecker:55 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" " o When checking 'news:' links the given NNTP host doesn't need to be the\n" " same as the host of the user browsing your pages.\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" #: ../linkchecker:71 #, fuzzy msgid "" "PROXY SUPPORT\n" "To use a proxy on Unix or Windows set $http_proxy, $https_proxy or " "$ftp_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, and gconf or KDE on Linux systems.\n" "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, " "$https_proxy oder $ftp_proxy\n" "auf die Proxy URL. Die URL sollte die Form \"[:" "@][:]\"\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" #: ../linkchecker:96 msgid "" "REGULAR EXPRESSIONS\n" "Only Python regular expressions are accepted by LinkChecker.\n" "See http://www.amk.ca/python/howto/regex/ 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 http://www.amk.ca/python/howto/regex/ 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" #: ../linkchecker:105 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" #: ../linkchecker:133 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" #: ../linkchecker:140 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" #: ../linkchecker:164 #, 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" "blacklist\n" " Suitable for cron jobs. Logs the check result into a file\n" " ~/.linkchecker/blacklist which only contains entries with invalid\n" " 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 --complete 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 Vater-Kind Beziehungen zwischen verknüpften URLs als GML " "Graphen aus.\n" "dot Gebe Vater-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" "blacklist\n" " Für Cronjobs geeignet. Gibt das Prüfergebnis in eine Datei ~/." "linkchecker/blacklist 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" #: ../linkchecker:189 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" #: ../linkchecker:219 msgid "General options" msgstr "Allgemeine Optionen" #: ../linkchecker:223 #, fuzzy, python-format msgid "" "Use FILENAME as configuration file. Per default LinkChecker uses\n" "~/.linkchecker/linkcheckerrc (under Windows\n" "%%HOMEPATH%%\\.linkchecker\\linkcheckerrc)." msgstr "" "Benutze FILENAME als Konfigurationsdatei. Standardmäßig benutzt\n" " LinkChecker ~/.linkchecker/linkcheckerrc\n" "(unter Windows %HOMEPATH%\\.linkchecker\\linkcheckerrc)." #: ../linkchecker:228 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." #: ../linkchecker:231 msgid "Print version and exit." msgstr "Drucke die Version und beende das Programm." #: ../linkchecker:234 #, fuzzy msgid "Print available check plugins and exit." msgstr "Drucke die Version und beende das Programm." #: ../linkchecker:237 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." #: ../linkchecker:240 msgid "Output options" msgstr "Ausgabeoptionen" #: ../linkchecker:251 #, 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." #: ../linkchecker:262 #, python-format msgid "" "Output to a file linkchecker-out.TYPE, $HOME/.linkchecker/blacklist for\n" "'blacklist' 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 http://docs.python.org/lib/standard-encodings." "html.\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" "$HOME/.linkchecker/blacklist\n" "bei 'blacklist' 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 http://docs.python.org/lib/standard-" "encodings.html 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." #: ../linkchecker:276 msgid "Do not print check status messages." msgstr "Gebe keine Statusmeldungen aus." #: ../linkchecker:278 msgid "Don't log warnings. Default is to log warnings." msgstr "Gebe keine Warnungen aus. Standard ist die Ausgabe von Warnungen." #: ../linkchecker:281 #, 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 http://docs.python.org/lib/standard-encodings." "html." 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 http://docs.python.org/lib/standard-" "encodings.html aufgeführt." #: ../linkchecker:291 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." #: ../linkchecker:300 msgid "Log all URLs. Default is to log only errors and warnings." msgstr "Logge alle URLs. Standard ist es, nur fehlerhafte URLs zu loggen." #: ../linkchecker:312 msgid "Checking options" msgstr "Prüf-Optionen" #: ../linkchecker:321 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." #: ../linkchecker:325 msgid "Disable robots.txt checks" msgstr "" #: ../linkchecker:327 msgid "Check external URLs." msgstr "" #: ../linkchecker:330 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." #: ../linkchecker:334 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." #: ../linkchecker:338 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." #: ../linkchecker:344 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." #: ../linkchecker:354 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." #: ../linkchecker:359 #, python-format msgid "" "Set the timeout for connection attempts in seconds. The default\n" "timeout is %d seconds." msgstr "" "Setze den Timeout für Verbindungen in Sekunden. Der Standard\n" "Timeout ist %d Sekunden." #: ../linkchecker:363 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." #: ../linkchecker:368 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." #: ../linkchecker:402 #, python-format msgid "Invalid debug level %(level)r" msgstr "Ungültiger Debuglevel %(level)r" #: ../linkchecker:415 #, python-format msgid "Unreadable config file: %r" msgstr "Nicht lesbare Konfigurationsdatei: %r" #: ../linkchecker:423 msgid "Running with python -O disables debugging." msgstr "Die Option python -O verhindert das Debuggen." #: ../linkchecker:453 ../linkchecker:485 #, 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" #: ../linkchecker:457 ../linkchecker:491 #, 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" #: ../linkchecker:503 #, python-format msgid "Enter LinkChecker HTTP/FTP password for user %(user)s:" msgstr "Gebe LinkChecker HTTP/FTP Passwort für Benutzer %(user)s ein:" #: ../linkchecker:506 msgid "Enter LinkChecker HTTP/FTP password:" msgstr "Gebe LinkChecker HTTP/FTP Passwort ein:" #: ../linkchecker:525 #, python-format msgid "Illegal argument %(arg)r for option %(option)s" msgstr "Ungültiges Argument %(arg)r für Option %(option)s" #: ../linkchecker:542 #, 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:" #: ../linkchecker:551 #, fuzzy, python-format msgid "Could not read cookie file %s" msgstr "Konnte Cookie-Datei nicht parsen: %s" #: ../linkchecker:576 msgid "no files or URLs given" msgstr "keine Dateien oder URLs angegeben" #: ../linkchecker:581 #, 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." #: ../linkchecker:586 msgid "Canceled." msgstr "Abgebrochen." #: ../linkchecker:590 #, fuzzy msgid "" "The `yappi' Python module is not installed, therefore the --profile option " "is disabled." msgstr "" "Das `cProfile' Python Modul ist nicht installiert, deshalb ist die --profile " "Option deaktiviert." #: ../linkchecker:606 msgid "Dumping memory statistics..." msgstr "Generiere Speicherabzug..." #: ../linkchecker:608 #, python-format msgid "The memory dump has been written to `%(filename)s'." msgstr "Der Speicherabzug wurde in Datei `%(filename)s' geschrieben." #: /usr/lib/python3.8/argparse.py:295 #, fuzzy msgid "usage: " msgstr "Syntax: %s\n" #: /usr/lib/python3.8/argparse.py:846 msgid ".__call__() not defined" msgstr "" #: /usr/lib/python3.8/argparse.py:1149 #, python-format msgid "unknown parser %(parser_name)r (choices: %(choices)s)" msgstr "" #: /usr/lib/python3.8/argparse.py:1209 #, python-format msgid "argument \"-\" with mode %r" msgstr "" #: /usr/lib/python3.8/argparse.py:1218 #, python-format msgid "can't open '%(filename)s': %(error)s" msgstr "" #: /usr/lib/python3.8/argparse.py:1427 #, python-format msgid "cannot merge actions - two groups are named %r" msgstr "" #: /usr/lib/python3.8/argparse.py:1465 msgid "'required' is an invalid argument for positionals" msgstr "" #: /usr/lib/python3.8/argparse.py:1487 #, python-format msgid "" "invalid option string %(option)r: must start with a character " "%(prefix_chars)r" msgstr "" #: /usr/lib/python3.8/argparse.py:1507 #, python-format msgid "dest= is required for options like %r" msgstr "" #: /usr/lib/python3.8/argparse.py:1524 #, fuzzy, python-format msgid "invalid conflict_resolution value: %r" msgstr "ungültiger \"notAfter\" Zertifikatwert %r" #: /usr/lib/python3.8/argparse.py:1542 #, python-format msgid "conflicting option string: %s" msgid_plural "conflicting option strings: %s" msgstr[0] "" msgstr[1] "" #: /usr/lib/python3.8/argparse.py:1608 msgid "mutually exclusive arguments must be optional" msgstr "" #: /usr/lib/python3.8/argparse.py:1671 #, fuzzy msgid "positional arguments" msgstr "%s Option erfordert ein Argument" #: /usr/lib/python3.8/argparse.py:1672 #, fuzzy msgid "optional arguments" msgstr "%s Option erfordert ein Argument" #: /usr/lib/python3.8/argparse.py:1687 msgid "show this help message and exit" msgstr "Zeige diesen Hilfetext und beende" #: /usr/lib/python3.8/argparse.py:1718 msgid "cannot have multiple subparser arguments" msgstr "" #: /usr/lib/python3.8/argparse.py:1770 /usr/lib/python3.8/argparse.py:2277 #, python-format msgid "unrecognized arguments: %s" msgstr "" #: /usr/lib/python3.8/argparse.py:1867 #, python-format msgid "not allowed with argument %s" msgstr "" #: /usr/lib/python3.8/argparse.py:1913 /usr/lib/python3.8/argparse.py:1927 #, python-format msgid "ignored explicit argument %r" msgstr "" #: /usr/lib/python3.8/argparse.py:2034 #, python-format msgid "the following arguments are required: %s" msgstr "" #: /usr/lib/python3.8/argparse.py:2049 #, python-format msgid "one of the arguments %s is required" msgstr "" #: /usr/lib/python3.8/argparse.py:2092 msgid "expected one argument" msgstr "" #: /usr/lib/python3.8/argparse.py:2093 msgid "expected at most one argument" msgstr "" #: /usr/lib/python3.8/argparse.py:2094 msgid "expected at least one argument" msgstr "" #: /usr/lib/python3.8/argparse.py:2098 #, python-format msgid "expected %s argument" msgid_plural "expected %s arguments" msgstr[0] "" msgstr[1] "" #: /usr/lib/python3.8/argparse.py:2156 #, fuzzy, python-format msgid "ambiguous option: %(option)s could match %(matches)s" msgstr "Mehrdeutige Option: %s (%s?)" #: /usr/lib/python3.8/argparse.py:2220 #, python-format msgid "unexpected option string: %s" msgstr "" #: /usr/lib/python3.8/argparse.py:2417 #, python-format msgid "%r is not callable" msgstr "" #: /usr/lib/python3.8/argparse.py:2434 #, fuzzy, python-format msgid "invalid %(type)s value: %(value)r" msgstr "Option %s: Ungültiger %s Wert: %r" #: /usr/lib/python3.8/argparse.py:2445 #, fuzzy, python-format msgid "invalid choice: %(value)r (choose from %(choices)s)" msgstr "Option %s: ungültige Auswahl: %r (wähle von %s)" #: /usr/lib/python3.8/argparse.py:2521 #, fuzzy, python-format msgid "%(prog)s: error: %(message)s\n" msgstr "ignore%d: Syntaxfehler %s\n" #, python-format #~ msgid "Support this project at %s" #~ msgstr "Unterstütze dieses Projekt unter %s" #, python-format #~ msgid "Support this project at %(url)s" #~ msgstr "Unterstütze dieses Projekt unter %(url)s" #~ msgid "show program's version number and exit" #~ msgstr "Zeige Programmversion und beende" linkchecker-10.0.1/po/es.mo000066400000000000000000000140631400504243600154370ustar00rootroot00000000000000L|epq ""6 ?If  #!*Li7 #. 8 = ,[   % 0 #  N m x "   *    +  u  )      "  ; Z d x   s ? X*f+* ( 5$A*f  +$*9A,T'': &% L)Y3 (( !,(>U;i MW"r3 .  #0  % 1'="e % CA 1/+&!:3<8$B=2#%-(JKI*H79L6 F);  4 ,5D@E" G0'?>.%(scheme)s URL ignored.%.3f seconds%d error found%d errors found%d hour%d hours%d link checked.%d links checked.%d minute%d minutes%d second%d seconds%d warning found%d warnings found, col %d, line %dAnchor `%(name)s' not found.Article number %(num)s found.BaseCRITICALCache keyCanceled.Checking optionsDEBUGDo not print check status messages.ERROREffective URL %(url)r.ErrorError: %(msg)sExternGeneral optionsGet the newest version at %(url)sGet the newest version at %sGot no answer from FTP serverHappy birthday for LinkChecker, I'm %d years old today!Host is emptyHostname not foundINFOIgnoring proxy setting `%(proxy)s'.Illegal argument %(arg)r for option %(option)sInfoInvalid debug level %(level)rMissing trailing directory slash in ftp url.NOTSETNameNo MX mail host for %(domain)s found.No NNTP server was specified, skipping this URL.No newsgroup specified in NNTP URL.Output optionsOverwrite profiling file %(file)r? Press Ctrl-C to cancel, RETURN to continue.Parent URLPrint version and exit.Python %(version)s on %(platform)sReal URLRedirected to `%(url)s'.Remote host has closed connection: %(msg)sResultSpecify an NNTP server for 'news:...' links. Default is the environment variable NNTP_SERVER. If no host is given, only the syntax of the link is checked.Start checking at %sStopped checking at %(time)s (%(duration)s)System info:That's it.The URL has been ignored.The URL path %(path)r is not the same as the system path %(realpath)r. You should always use the system path in URLs.URLURL is emptyURL is unrecognized or has invalid syntaxUsing proxy `%(proxy)s'.ValidWARNWARNINGWarningWrite comments and bugs to %(url)sWrite comments and bugs to %screated by %(app)s at %(time)sdirectoryempty url was givenno files or URLs givenno url was givenruntime %sshow this help message and exitProject-Id-Version: linkchecker 2.8 Report-Msgid-Bugs-To: bastian.kleineidam@web.de PO-Revision-Date: 2011-02-16 15:24+0100 Last-Translator: Bastian Kleineidam Language-Team: Spanish Language: es MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(1 < n); URL %(scheme)s ignorado.%.3f segundos%d error encontrado%d errores encontrados%d horas%d horas%d enlace chequeado.%d enlaces chequeados.%d minutos%d minutos%d segundos%d segundos%d error encontrado%d errores encontrados, columna %d, línea %dNo se encontró el ancla `%(name)s'.Se encontró el artículo número %(num)s.BaseCRÍTICOLlave del "cache"Cancelado.Opciones de chequeoDEPURACIÓNNo imprimir mensajes de estado del chequeo.ERRORURL efectivo %(url)r.ErrorError: %(msg)sExternoOpciones generalesObtenga la versión más reciente en %(url)sObtenga la versión más reciente en %sNo se obtuvo respuesta del servidor FTP¡Cumpleaños feliz para LinkChecker, cumplo %d años hoy!El servidor está vacíoNo se encontró el nombre del servidorINFORMACIÓNIgnorando el ajuste del proxy `%(proxy)s'Argumento ilegal %(arg)r para la opción %(option)sInformaciónNivel de depuración inválido %(level)rFalta el "slash" final en el URL de FTP.NODEFINIDONombreNo se encontró servidor MX para %(domain)s.No se especificó un servidor NNTP, pasando por alto este URL.No se especificó ningún grupo de noticias en el URL NTTP.Opciones de salida¿Sobreescribir archivo %(file)r de perfilamiento? Presione Ctrl-C para cancelar, RETORNO para continuar.URL padreImprimir versión y salir.Pitón %(version)s en %(platform)sURL realRedireccionado a `%(url)s'.El servidor remoto ha cerrado la conexión: %(msg)sResultadoEspecificar un servidor NNTP para enlaces 'news:...'. Por omisión es la variable del entorno NNTP_SERVER. Si no se da un anfitrión, sólo se chequea la sintaxis del enlace.Se comenzó el chequeo en %sSe paró el chequeo en %(time)s (%(duration)s)Información del sistema:Eso es.URL ignorado.El camino %(path)r del URL no es el mismo que el camino %(realpath)r del sistema. Debería usar siempre el camino del sistema en los URLs.URLEl URL está vacíoNo se reconoce el URL o tiene sintaxis inválidaUsando Proxy `%(proxy)s'.VálidoADVERTENCIAADVERTENCIAAdvertenciaEscriba comentarios y errores a %(url)sEscriba comentarios y errores a %scrado por %(app)s en %(time)sdirectoriose dió un URL vacíono se han dado archivos o URLsno se dió un URLtiempo de corrida %smostrar este mensaje de ayuda y salirlinkchecker-10.0.1/po/es.po000066400000000000000000001463531400504243600154520ustar00rootroot00000000000000# 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 2.8\n" "Report-Msgid-Bugs-To: bastian.kleineidam@web.de\n" "POT-Creation-Date: 2020-06-19 16:25+0100\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/configuration/confparse.py:62 #, python-format msgid "Error parsing configuration: %s" msgstr "" #: ../linkcheck/configuration/confparse.py:69 #, python-format msgid "invalid empty value for %s: %s\n" msgstr "" #: ../linkcheck/configuration/confparse.py:83 #: ../linkcheck/plugins/sslcertcheck.py:108 #, python-format msgid "invalid value for %s: %d must not be less than %d" msgstr "" #: ../linkcheck/configuration/confparse.py:86 #, python-format msgid "invalid value for %s: %d must not be greater than %d" msgstr "" #: ../linkcheck/configuration/confparse.py:175 #, python-format msgid "missing auth part in entry %(val)r" msgstr "" #: ../linkcheck/configuration/confparse.py:181 #, python-format msgid "invalid login URL `%s'. Only HTTP and HTTPS URLs are supported." msgstr "" #: ../linkcheck/configuration/confparse.py:206 #, python-format msgid "For example execute 'chmod go-rw %s'." msgstr "" #: ../linkcheck/configuration/confparse.py:251 #, python-format msgid "See %(url)s for more info on setting file permissions." msgstr "" #: ../linkcheck/configuration/__init__.py:242 #, python-format msgid "Configuration file %r does not exist." msgstr "" #: ../linkcheck/configuration/__init__.py:244 #, python-format msgid "Configuration file %r is not readable." msgstr "" #: ../linkcheck/configuration/__init__.py:254 msgid "missing user or URL pattern in authentication data." msgstr "" #: ../linkcheck/configuration/__init__.py:293 msgid "activating text logger output." msgstr "" #: ../linkcheck/configuration/__init__.py:303 msgid "no CGI password fieldname given for login URL." msgstr "" #: ../linkcheck/configuration/__init__.py:307 msgid "no CGI user fieldname given for login URL." msgstr "" #: ../linkcheck/configuration/__init__.py:311 msgid "no user/password authentication data found for login URL." msgstr "" #: ../linkcheck/configuration/__init__.py:314 msgid "login URL is not a HTTP URL." msgstr "" #: ../linkcheck/configuration/__init__.py:318 msgid "login URL is incomplete." msgstr "" #: ../linkcheck/configuration/__init__.py:322 #, python-format msgid "disabling login URL %(url)s." msgstr "" #: ../linkcheck/configuration/__init__.py:384 #, python-format msgid "could not create plugin directory %(dirname)r: %(errmsg)r" msgstr "" #: ../linkcheck/configuration/__init__.py:425 #, python-format msgid "" "could not copy initial configuration file %(src)r to %(dst)r: %(errmsg)r" msgstr "" #: ../linkcheck/lc_cgi.py:207 #, fuzzy, python-format msgid "unsupported language %r" msgstr "lenguaje sin soporte" #: ../linkcheck/lc_cgi.py:212 msgid "empty url was given" msgstr "se dió un URL vacío" #: ../linkcheck/lc_cgi.py:214 #, fuzzy, python-format msgid "disallowed url %r was given" msgstr "se dió un URL no permitido" #: ../linkcheck/lc_cgi.py:216 msgid "no url was given" msgstr "no se dió un URL" #: ../linkcheck/lc_cgi.py:221 #, fuzzy, python-format msgid "invalid recursion level %r" msgstr "nivel de recursión inválido" #: ../linkcheck/lc_cgi.py:227 #, fuzzy, python-format msgid "invalid %s option %r" msgstr "opción de registro %r inválida" #: ../linkcheck/lc_cgi.py:251 #, 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/__init__.py:117 msgid "CRITICAL" msgstr "CRÍTICO" #: ../linkcheck/__init__.py:118 msgid "ERROR" msgstr "ERROR" #: ../linkcheck/__init__.py:119 msgid "WARN" msgstr "ADVERTENCIA" #: ../linkcheck/__init__.py:120 msgid "WARNING" msgstr "ADVERTENCIA" #: ../linkcheck/__init__.py:121 msgid "INFO" msgstr "INFORMACIÓN" #: ../linkcheck/__init__.py:122 msgid "DEBUG" msgstr "DEPURACIÓN" #: ../linkcheck/__init__.py:123 msgid "NOTSET" msgstr "NODEFINIDO" #: ../linkcheck/__init__.py:135 msgid "Running as root user; dropping privileges by changing user to nobody." msgstr "" #: ../linkcheck/cmdline.py:59 #, python-format msgid "Error: %(msg)s" msgstr "Error: %(msg)s" #: ../linkcheck/cmdline.py:60 #, fuzzy, python-format msgid "Execute '%(program)s -h' for help" msgstr "Ejecute 'linkchecker -h' para obtener ayuda" #: ../linkcheck/strformat.py:247 #, python-format msgid "%(prefix)s%(duration).02f seconds" msgstr "" #: ../linkcheck/strformat.py:250 #, python-format msgid "%d second" msgid_plural "%d seconds" msgstr[0] "%d segundos" msgstr[1] "%d segundos" #: ../linkcheck/strformat.py:251 #, python-format msgid "%d minute" msgid_plural "%d minutes" msgstr[0] "%d minutos" msgstr[1] "%d minutos" #: ../linkcheck/strformat.py:252 #, python-format msgid "%d hour" msgid_plural "%d hours" msgstr[0] "%d horas" msgstr[1] "%d horas" #: ../linkcheck/strformat.py:253 #, python-format msgid "%d day" msgid_plural "%d days" msgstr[0] "" msgstr[1] "" #: ../linkcheck/strformat.py:254 #, python-format msgid "%d year" msgid_plural "%d years" msgstr[0] "" msgstr[1] "" #: ../linkcheck/strformat.py:323 #, python-format msgid "" "Could not import %(module)s for %(feature)s. Install %(module)s from %(url)s " "to use this feature." msgstr "" #: ../linkcheck/director/aggregator.py:160 msgid "These URLs are still active:" msgstr "" #: ../linkcheck/director/aggregator.py:167 #, python-format msgid "" "%(num)d URLs are still active. After a timeout of %(timeout)s the active " "URLs will stop." msgstr "" #: ../linkcheck/director/__init__.py:35 #, python-format msgid "Error using login URL: %(msg)s." msgstr "" #: ../linkcheck/director/__init__.py:41 #, python-format msgid "Error starting log output: %(msg)s." msgstr "" #: ../linkcheck/director/__init__.py:56 msgid "" "Could not start a new thread. Check that the current user is allowed to " "start new threads." msgstr "" #: ../linkcheck/director/__init__.py:88 #, 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:90 msgid "another interrupt will exit immediately" msgstr "" #: ../linkcheck/director/__init__.py:106 msgid "user abort; force shutdown" 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:41 #, 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:43 #, python-format msgid "%4d link" msgid_plural "%4d links" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:45 #, python-format msgid "%3d URL" msgid_plural "%3d URLs" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:47 #, python-format msgid "runtime %s" msgstr "tiempo de corrida %s" #: ../linkcheck/director/console.py:67 #, 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:114 msgid "Default locale:" msgstr "" #: ../linkcheck/director/console.py:136 msgid "System info:" msgstr "Información del sistema:" #: ../linkcheck/director/console.py:138 msgid "Released on:" msgstr "" #: ../linkcheck/director/console.py:139 ../linkchecker:404 #, python-format msgid "Python %(version)s on %(platform)s" msgstr "Pitón %(version)s en %(platform)s" #: ../linkcheck/director/console.py:145 #, fuzzy msgid "Local time:" msgstr "Tiempo de bajada" #: ../linkcheck/director/console.py:146 msgid "sys.argv:" msgstr "" #: ../linkcheck/director/console.py:151 msgid "released" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:68 msgid "valid HTML syntax" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:74 #, fuzzy, python-format msgid "HTML syntax check plugin error: %(msg)s " msgstr "Error de sintaxis en %(arg)r: %(msg)s" #: ../linkcheck/plugins/syntaxchecks.py:105 msgid "valid CSS syntax" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:111 #, fuzzy, python-format msgid "CSS syntax check plugin error: %(msg)s " msgstr "Error de sintaxis en %(arg)r: %(msg)s" #: ../linkcheck/plugins/syntaxchecks.py:119 #, python-format msgid "%(w3type)s validation error at line %(line)s col %(column)s: %(msg)s" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:63 msgid "certificate did not include \"notAfter\" information" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:66 msgid "SSL verification is disabled; enable the sslverify option" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:77 #, python-format msgid "Invalid SSL certficate \"notAfter\" value %r" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:86 #, python-format msgid "SSL certficate is expired on %(expire)s." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:91 #, python-format msgid "SSL certificate expires on %(expire)s and is only %(valid)s valid." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:94 #, python-format msgid "SSL certificate expires on %(expire)s and is %(valid)s valid." msgstr "" #: ../linkcheck/plugins/anchorcheck.py:59 #, python-format msgid "Anchor `%(name)s' not found." msgstr "No se encontró el ancla `%(name)s'." #: ../linkcheck/plugins/anchorcheck.py:60 #, python-format msgid "Available anchors: %(anchors)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:162 msgid "only one of TCPSocket and LocalSocket must be enabled" msgstr "" #: ../linkcheck/plugins/viruscheck.py:191 msgid "one of TCPSocket or LocalSocket must be enabled" msgstr "" #: ../linkcheck/plugins/viruscheck.py:226 #, fuzzy msgid "Could not connect to ClamAV daemon." msgstr "No pude conectar, pero la sintaxis es correcta" #: ../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/locationinfo.py:46 #, fuzzy, python-format msgid "URL is located in %(location)s." msgstr "El URL está localizado en %(country)s." #: ../linkcheck/checker/fileurl.py:118 #, 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:152 #, fuzzy msgid "Added trailing slash to directory." msgstr "Se adicionó \"slash\" final al directorio." #: ../linkcheck/checker/fileurl.py:174 msgid "" "local files are only checked without parent URL or when the parent URL is " "also a file" msgstr "" #: ../linkcheck/checker/fileurl.py:177 msgid "directory" msgstr "directorio" #: ../linkcheck/checker/fileurl.py:194 #, 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/ftpurl.py:91 msgid "Got no answer from FTP server" msgstr "No se obtuvo respuesta del servidor FTP" #: ../linkcheck/checker/ftpurl.py:94 #, 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:140 msgid "Missing trailing directory slash in ftp url." msgstr "Falta el \"slash\" final en el URL de FTP." #: ../linkcheck/checker/ftpurl.py:201 msgid "FTP file size too large" msgstr "" #: ../linkcheck/checker/mailtourl.py:84 #, fuzzy, python-format msgid "No mail addresses or email subject found in `%(url)s'." msgstr "No se encontraron direcciones." #: ../linkcheck/checker/mailtourl.py:125 #, python-format msgid "Error parsing CGI values: %s" msgstr "" #: ../linkcheck/checker/mailtourl.py:148 #, python-format msgid "" "Mail address `%(addr)s' too long. Allowed 256 chars, was %(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:152 #, python-format msgid "Missing `@' in mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:158 #, python-format msgid "Missing local part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:162 #, python-format msgid "Missing domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:166 #, python-format msgid "" "Local part of mail address `%(addr)s' too long. Allowed 64 chars, was " "%(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:170 #, python-format msgid "" "Domain part of mail address `%(addr)s' too long. Allowed 255 chars, was " "%(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:179 #, python-format msgid "Unquoted double quote or backslash in mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:184 #, python-format msgid "Local part of mail address `%(addr)s' may not start with a dot." msgstr "" #: ../linkcheck/checker/mailtourl.py:188 #, python-format msgid "Local part of mail address `%(addr)s' may not end with a dot." msgstr "" #: ../linkcheck/checker/mailtourl.py:192 #, python-format msgid "Local part of mail address `%(addr)s' may not contain two dots." msgstr "" #: ../linkcheck/checker/mailtourl.py:197 #, python-format msgid "" "Local part of mail address `%(addr)s' contains unquoted character `%(char)s." msgstr "" #: ../linkcheck/checker/mailtourl.py:209 #, python-format msgid "Domain part of mail address `%(addr)s' has invalid IP." msgstr "" #: ../linkcheck/checker/mailtourl.py:215 #, python-format msgid "Invalid domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:219 #, python-format msgid "Invalid top level domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:252 #, python-format msgid "No MX mail host for %(domain)s found." msgstr "No se encontró servidor MX para %(domain)s." #: ../linkcheck/checker/mailtourl.py:260 #, fuzzy, python-format msgid "No host for %(domain)s found." msgstr "No se encontró servidor MX para %(domain)s." #: ../linkcheck/checker/mailtourl.py:274 #, python-format msgid "Got invalid DNS answer %(answer)s for %(domain)s." msgstr "" #: ../linkcheck/checker/mailtourl.py:286 #, fuzzy msgid "Valid mail address syntax" msgstr "Sintaxis de correo inválida" #: ../linkcheck/checker/unknownurl.py:31 #, python-format msgid "%(scheme)s URL ignored." msgstr "URL %(scheme)s ignorado." #: ../linkcheck/checker/unknownurl.py:33 #, fuzzy msgid "ignored" msgstr "URL %s ignorado." #: ../linkcheck/checker/unknownurl.py:35 msgid "URL is unrecognized or has invalid syntax" msgstr "No se reconoce el URL o tiene sintaxis inválida" #: ../linkcheck/checker/const.py:102 msgid "The effective URL is different from the original." msgstr "" #: ../linkcheck/checker/const.py:104 msgid "Could not get the content of the URL." msgstr "" #: ../linkcheck/checker/const.py:105 msgid "The URL content size is too large." msgstr "" #: ../linkcheck/checker/const.py:106 msgid "The URL content size is zero." msgstr "" #: ../linkcheck/checker/const.py:107 msgid "The URL is longer than the recommended size." msgstr "" #: ../linkcheck/checker/const.py:108 msgid "The URL contains leading or trailing whitespace." msgstr "" #: ../linkcheck/checker/const.py:109 msgid "The file: URL is missing a trailing slash." msgstr "" #: ../linkcheck/checker/const.py:111 msgid "The file: path is not the same as the system specific path." 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:115 msgid "An error occurred while storing a cookie." msgstr "" #: ../linkcheck/checker/const.py:116 msgid "The URL has been ignored." msgstr "URL ignorado." #: ../linkcheck/checker/const.py:117 msgid "The mail MX host could not be found." msgstr "" #: ../linkcheck/checker/const.py:118 #, fuzzy msgid "No NNTP server was found." msgstr "No se especificó un servidor NNTP, pasando por alto este URL." #: ../linkcheck/checker/const.py:119 msgid "The NNTP newsgroup could not be found." msgstr "" #: ../linkcheck/checker/const.py:120 msgid "The IP is obfuscated." msgstr "" #: ../linkcheck/checker/const.py:121 msgid "XML could not be parsed." 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/checker/nntpurl.py:44 msgid "No NNTP server was specified, skipping this URL." msgstr "No se especificó un servidor NNTP, pasando por alto este URL." #: ../linkcheck/checker/nntpurl.py:54 #, python-format msgid "Article number %(num)s found." msgstr "Se encontró el artículo número %(num)s." #: ../linkcheck/checker/nntpurl.py:61 #, python-format msgid "News group %(name)s found." msgstr "" #: ../linkcheck/checker/nntpurl.py:64 msgid "No newsgroup specified in NNTP URL." msgstr "No se especificó ningún grupo de noticias en el URL NTTP." #: ../linkcheck/checker/nntpurl.py:88 #, 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." #: ../linkcheck/checker/urlbase.py:65 #, python-format msgid "URL has unparsable domain name: %(name)s" msgstr "" #: ../linkcheck/checker/urlbase.py:124 #, 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:127 msgid "filtered" msgstr "" #: ../linkcheck/checker/urlbase.py:162 #, python-format msgid "Leading or trailing whitespace in URL `%(url)s'." msgstr "" #: ../linkcheck/checker/urlbase.py:324 msgid "URL is empty" msgstr "El URL está vacío" #: ../linkcheck/checker/urlbase.py:338 #, python-format msgid "Effective URL %(url)r." msgstr "URL efectivo %(url)r." #: ../linkcheck/checker/urlbase.py:344 #, 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:390 #, 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:397 #, fuzzy msgid "URL has empty hostname" msgstr "El URL está vacío" #: ../linkcheck/checker/urlbase.py:421 #, python-format msgid "URL %(url)s has obfuscated IP address %(ip)s" msgstr "" #: ../linkcheck/checker/urlbase.py:456 msgid "Hostname not found" msgstr "No se encontró el nombre del servidor" #: ../linkcheck/checker/urlbase.py:459 #, python-format msgid "Bad hostname %(host)r: %(msg)s" msgstr "" #: ../linkcheck/checker/urlbase.py:475 #, fuzzy, python-format msgid "could not get content: %(msg)s" msgstr "no se pudo analizar el contenido: %(msg)r" #: ../linkcheck/checker/urlbase.py:526 #, 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:619 msgid "Content size is zero." msgstr "" #: ../linkcheck/checker/urlbase.py:649 ../linkcheck/checker/httpurl.py:313 msgid "File size too large" msgstr "" #: ../linkcheck/checker/urlbase.py:717 #, python-format msgid "URL has unparsable domain name: %(domain)s" msgstr "" #: ../linkcheck/checker/proxysupport.py:43 #, python-format msgid "Proxy value `%(proxy)s' must start with 'http:' or 'https:'." msgstr "" #: ../linkcheck/checker/proxysupport.py:49 #, python-format msgid "Ignoring proxy setting `%(proxy)s'." msgstr "Ignorando el ajuste del proxy `%(proxy)s'" #: ../linkcheck/checker/proxysupport.py:54 #, python-format msgid "Using proxy `%(proxy)s'." msgstr "Usando Proxy `%(proxy)s'." #: ../linkcheck/checker/itmsservicesurl.py:32 msgid "Missing required url parameter" msgstr "" #: ../linkcheck/checker/telneturl.py:52 msgid "Host is empty" msgstr "El servidor está vacío" #: ../linkcheck/checker/httpurl.py:125 #, 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:126 msgid "syntax OK" msgstr "" #: ../linkcheck/checker/httpurl.py:257 #, python-format msgid "Redirected to `%(url)s'." msgstr "Redireccionado a `%(url)s'." #: ../linkcheck/checker/httpurl.py:297 msgid "OK" msgstr "" #: ../linkcheck/logger/text.py:98 ../linkcheck/logger/__init__.py:380 #, python-format msgid "Get the newest version at %(url)s" msgstr "Obtenga la versión más reciente en %(url)s" #: ../linkcheck/logger/text.py:100 ../linkcheck/logger/__init__.py:382 #, python-format msgid "Write comments and bugs to %(url)s" msgstr "Escriba comentarios y errores a %(url)s" #: ../linkcheck/logger/text.py:104 ../linkcheck/logger/html.py:122 #, python-format msgid "Start checking at %s" msgstr "Se comenzó el chequeo en %s" #: ../linkcheck/logger/text.py:158 ../linkcheck/logger/html.py:192 #, python-format msgid ", line %d" msgstr ", línea %d" #: ../linkcheck/logger/text.py:160 ../linkcheck/logger/html.py:194 #, python-format msgid ", col %d" msgstr ", columna %d" #: ../linkcheck/logger/text.py:162 ../linkcheck/logger/html.py:196 #, fuzzy, python-format msgid ", page %d" msgstr ", línea %d" #: ../linkcheck/logger/text.py:178 ../linkcheck/logger/text.py:190 #: ../linkcheck/logger/html.py:220 ../linkcheck/logger/html.py:232 #, python-format msgid "%.3f seconds" msgstr "%.3f segundos" #: ../linkcheck/logger/text.py:214 ../linkcheck/logger/html.py:261 msgid "Valid" msgstr "Válido" #: ../linkcheck/logger/text.py:217 ../linkcheck/logger/html.py:266 msgid "Error" msgstr "Error" #: ../linkcheck/logger/text.py:226 msgid "The check has been interrupted; results are not complete." msgstr "" #: ../linkcheck/logger/text.py:227 ../linkcheck/logger/html.py:291 msgid "That's it." msgstr "Eso es." #: ../linkcheck/logger/text.py:228 #, fuzzy, python-format msgid "%d link" msgid_plural "%d links" msgstr[0] "%d enlace chequeado." msgstr[1] "%d enlaces chequeados." #: ../linkcheck/logger/text.py:232 #, python-format msgid "in %d URL" msgid_plural "in %d URLs" msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/text.py:235 ../linkcheck/logger/html.py:296 #, python-format msgid "%d warning found" msgid_plural "%d warnings found" msgstr[0] "%d error encontrado" msgstr[1] "%d errores encontrados" #: ../linkcheck/logger/text.py:243 ../linkcheck/logger/html.py:299 #, python-format msgid " (%d ignored or duplicates not printed)" msgstr "" #: ../linkcheck/logger/text.py:246 ../linkcheck/logger/html.py:302 #, python-format msgid "%d error found" msgid_plural "%d errors found" msgstr[0] "%d error encontrado" msgstr[1] "%d errores encontrados" #: ../linkcheck/logger/text.py:254 ../linkcheck/logger/html.py:305 #, python-format msgid " (%d duplicates not printed)" msgstr "" #: ../linkcheck/logger/text.py:259 ../linkcheck/logger/html.py:311 #, python-format msgid "There was %(num)d internal error." msgid_plural "There were %(num)d internal errors." msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/text.py:263 ../linkcheck/logger/__init__.py:390 #: ../linkcheck/logger/html.py:316 #, python-format msgid "Stopped checking at %(time)s (%(duration)s)" msgstr "Se paró el chequeo en %(time)s (%(duration)s)" #: ../linkcheck/logger/text.py:270 msgid "Statistics:" msgstr "" #: ../linkcheck/logger/text.py:272 #, python-format msgid "Downloaded: %s." msgstr "" #: ../linkcheck/logger/text.py:275 ../linkcheck/logger/html.py:276 #, 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/text.py:278 ../linkcheck/logger/html.py:280 #, python-format msgid "URL lengths: min=%(min)d, max=%(max)d, avg=%(avg)d." msgstr "" #: ../linkcheck/logger/text.py:283 ../linkcheck/logger/html.py:285 msgid "No statistics available since no URLs were checked." 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:278 #, 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:377 #, python-format msgid "created by %(app)s at %(time)s" msgstr "crado por %(app)s en %(time)s" #: ../linkcheck/logger/html.py:273 msgid "Statistics" msgstr "" #: ../linkcheck/logger/html.py:293 #, 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:321 #, python-format msgid "Get the newest version at %s" msgstr "Obtenga la versión más reciente en %s" #: ../linkcheck/logger/html.py:324 #, python-format msgid "Write comments and bugs to %s" msgstr "Escriba comentarios y errores a %s" #: ../linkchecker:55 #, 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" " o When checking 'news:' links the given NNTP host doesn't need to be the\n" " same as the host of the user browsing your pages.\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" #: ../linkchecker:71 msgid "" "PROXY SUPPORT\n" "To use a proxy on Unix or Windows set $http_proxy, $https_proxy or " "$ftp_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, and gconf or KDE on Linux systems.\n" "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 "" #: ../linkchecker:96 msgid "" "REGULAR EXPRESSIONS\n" "Only Python regular expressions are accepted by LinkChecker.\n" "See http://www.amk.ca/python/howto/regex/ 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 "" #: ../linkchecker:105 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 "" #: ../linkchecker:133 #, 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" #: ../linkchecker:140 #, 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" #: ../linkchecker:164 #, 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" "blacklist\n" " Suitable for cron jobs. Logs the check result into a file\n" " ~/.linkchecker/blacklist which only contains entries with invalid\n" " 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" #: ../linkchecker:189 msgid "" "IGNORE WARNINGS\n" "The following warnings are recognized in the 'ignorewarnings' config\n" "file entry:\n" msgstr "" #: ../linkchecker:219 msgid "General options" msgstr "Opciones generales" #: ../linkchecker:223 #, fuzzy, python-format msgid "" "Use FILENAME as configuration file. Per default LinkChecker uses\n" "~/.linkchecker/linkcheckerrc (under Windows\n" "%%HOMEPATH%%\\.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)." #: ../linkchecker:228 #, 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." #: ../linkchecker:231 msgid "Print version and exit." msgstr "Imprimir versión y salir." #: ../linkchecker:234 #, fuzzy msgid "Print available check plugins and exit." msgstr "Imprimir versión y salir." #: ../linkchecker:237 msgid "Read list of white-space separated URLs to check from stdin." msgstr "" #: ../linkchecker:240 msgid "Output options" msgstr "Opciones de salida" #: ../linkchecker:251 #, 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." #: ../linkchecker:262 #, fuzzy, python-format msgid "" "Output to a file linkchecker-out.TYPE, $HOME/.linkchecker/blacklist for\n" "'blacklist' 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 http://docs.python.org/lib/standard-encodings." "html.\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'." #: ../linkchecker:276 msgid "Do not print check status messages." msgstr "No imprimir mensajes de estado del chequeo." #: ../linkchecker:278 msgid "Don't log warnings. Default is to log warnings." msgstr "" #: ../linkchecker:281 #, 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 http://docs.python.org/lib/standard-encodings." "html." 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." #: ../linkchecker:291 #, 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." #: ../linkchecker:300 #, 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." #: ../linkchecker:312 msgid "Checking options" msgstr "Opciones de chequeo" #: ../linkchecker:321 msgid "" "Read a file with initial cookie data. The cookie data format is\n" "explained below." msgstr "" #: ../linkchecker:325 msgid "Disable robots.txt checks" msgstr "" #: ../linkchecker:327 msgid "Check external URLs." msgstr "" #: ../linkchecker:330 msgid "" "Only check syntax of URLs matching the given regular expression.\n" " This option can be given multiple times." msgstr "" #: ../linkchecker:334 msgid "" "Check but do not recurse into URLs matching the given regular\n" "expression. This option can be given multiple times." msgstr "" #: ../linkchecker:338 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." #: ../linkchecker:344 #, 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." #: ../linkchecker:354 #, 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." #: ../linkchecker:359 #, fuzzy, python-format msgid "" "Set the timeout for connection attempts in seconds. The default\n" "timeout is %d 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." #: ../linkchecker:363 #, 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." #: ../linkchecker:368 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 "" #: ../linkchecker:402 #, python-format msgid "Invalid debug level %(level)r" msgstr "Nivel de depuración inválido %(level)r" #: ../linkchecker:415 #, python-format msgid "Unreadable config file: %r" msgstr "" #: ../linkchecker:423 msgid "Running with python -O disables debugging." msgstr "" #: ../linkchecker:453 ../linkchecker:485 #, 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" #: ../linkchecker:457 ../linkchecker:491 #, 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" #: ../linkchecker:503 #, python-format msgid "Enter LinkChecker HTTP/FTP password for user %(user)s:" msgstr "" #: ../linkchecker:506 msgid "Enter LinkChecker HTTP/FTP password:" msgstr "" #: ../linkchecker:525 #, python-format msgid "Illegal argument %(arg)r for option %(option)s" msgstr "Argumento ilegal %(arg)r para la opción %(option)s" #: ../linkchecker:542 #, python-format msgid "Enter LinkChecker password for user %(user)s at %(strpattern)s:" msgstr "" #: ../linkchecker:551 #, fuzzy, python-format msgid "Could not read cookie file %s" msgstr "No se pudieron almacenar las \"cookies\": %s." #: ../linkchecker:576 msgid "no files or URLs given" msgstr "no se han dado archivos o URLs" #: ../linkchecker:581 #, 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." #: ../linkchecker:586 msgid "Canceled." msgstr "Cancelado." #: ../linkchecker:590 #, 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." #: ../linkchecker:606 msgid "Dumping memory statistics..." msgstr "" #: ../linkchecker:608 #, python-format msgid "The memory dump has been written to `%(filename)s'." msgstr "" #: /usr/lib/python3.8/argparse.py:295 #, fuzzy msgid "usage: " msgstr "Uso: %s\n" #: /usr/lib/python3.8/argparse.py:846 msgid ".__call__() not defined" msgstr "" #: /usr/lib/python3.8/argparse.py:1149 #, python-format msgid "unknown parser %(parser_name)r (choices: %(choices)s)" msgstr "" #: /usr/lib/python3.8/argparse.py:1209 #, python-format msgid "argument \"-\" with mode %r" msgstr "" #: /usr/lib/python3.8/argparse.py:1218 #, python-format msgid "can't open '%(filename)s': %(error)s" msgstr "" #: /usr/lib/python3.8/argparse.py:1427 #, python-format msgid "cannot merge actions - two groups are named %r" msgstr "" #: /usr/lib/python3.8/argparse.py:1465 msgid "'required' is an invalid argument for positionals" msgstr "" #: /usr/lib/python3.8/argparse.py:1487 #, python-format msgid "" "invalid option string %(option)r: must start with a character " "%(prefix_chars)r" msgstr "" #: /usr/lib/python3.8/argparse.py:1507 #, python-format msgid "dest= is required for options like %r" msgstr "" #: /usr/lib/python3.8/argparse.py:1524 #, python-format msgid "invalid conflict_resolution value: %r" msgstr "" #: /usr/lib/python3.8/argparse.py:1542 #, fuzzy, python-format msgid "conflicting option string: %s" msgid_plural "conflicting option strings: %s" msgstr[0] "Opciones deprecadas" msgstr[1] "Opciones deprecadas" #: /usr/lib/python3.8/argparse.py:1608 msgid "mutually exclusive arguments must be optional" msgstr "" #: /usr/lib/python3.8/argparse.py:1671 #, fuzzy msgid "positional arguments" msgstr "la opción %s requiere un argumento" #: /usr/lib/python3.8/argparse.py:1672 #, fuzzy msgid "optional arguments" msgstr "la opción %s requiere un argumento" #: /usr/lib/python3.8/argparse.py:1687 msgid "show this help message and exit" msgstr "mostrar este mensaje de ayuda y salir" #: /usr/lib/python3.8/argparse.py:1718 msgid "cannot have multiple subparser arguments" msgstr "" #: /usr/lib/python3.8/argparse.py:1770 /usr/lib/python3.8/argparse.py:2277 #, python-format msgid "unrecognized arguments: %s" msgstr "" #: /usr/lib/python3.8/argparse.py:1867 #, python-format msgid "not allowed with argument %s" msgstr "" #: /usr/lib/python3.8/argparse.py:1913 /usr/lib/python3.8/argparse.py:1927 #, python-format msgid "ignored explicit argument %r" msgstr "" #: /usr/lib/python3.8/argparse.py:2034 #, python-format msgid "the following arguments are required: %s" msgstr "" #: /usr/lib/python3.8/argparse.py:2049 #, python-format msgid "one of the arguments %s is required" msgstr "" #: /usr/lib/python3.8/argparse.py:2092 msgid "expected one argument" msgstr "" #: /usr/lib/python3.8/argparse.py:2093 msgid "expected at most one argument" msgstr "" #: /usr/lib/python3.8/argparse.py:2094 msgid "expected at least one argument" msgstr "" #: /usr/lib/python3.8/argparse.py:2098 #, python-format msgid "expected %s argument" msgid_plural "expected %s arguments" msgstr[0] "" msgstr[1] "" #: /usr/lib/python3.8/argparse.py:2156 #, fuzzy, python-format msgid "ambiguous option: %(option)s could match %(matches)s" msgstr "opción ambigua: %s (¿%s?)" #: /usr/lib/python3.8/argparse.py:2220 #, fuzzy, python-format msgid "unexpected option string: %s" msgstr "Opciones deprecadas" #: /usr/lib/python3.8/argparse.py:2417 #, python-format msgid "%r is not callable" msgstr "" #: /usr/lib/python3.8/argparse.py:2434 #, fuzzy, python-format msgid "invalid %(type)s value: %(value)r" msgstr "opción %s: inválido %s valor: %r" #: /usr/lib/python3.8/argparse.py:2445 #, fuzzy, python-format msgid "invalid choice: %(value)r (choose from %(choices)s)" msgstr "opción %s: opción inválida: %r (escoja de %s)" #: /usr/lib/python3.8/argparse.py:2521 #, fuzzy, python-format msgid "%(prog)s: error: %(message)s\n" msgstr "extern%d: error de sintaxis %s\n" #~ msgid "show program's version number and exit" #~ msgstr "mostrar número de versión del programa" linkchecker-10.0.1/po/fr.mo000066400000000000000000000120711400504243600154340ustar00rootroot00000000000000EDal  ,"=`u" "  ) 3>Oe#k!7 GUhm,r%0# & 5 @ X a h m   ( 4 A L P )]      "    % 9 J U u   )& P %c   7   4)Lv{ 9+18@,T';$;@1Ew~22+ &2 R ^hoL jw7!  9-5g ).+DA$9,-8<B ; / 125@'=?3(6)C&7 > ":04#%* !E%.3f seconds%d day%d days%d error found%d errors found%d hour%d hours%d link checked.%d links checked.%d minute%d minutes%d second%d seconds%d warning found%d warnings found%d year%d years, col %d, line %dAdded trailing slash to directory.Anchor `%(name)s' not found.BaseCRITICALCache keyCanceled.Check timeChecking optionsContent size is zero.DEBUGDo not print check status messages.ERRORErrorExternGeneral optionsGet the newest version at %(url)sGet the newest version at %sGot no answer from FTP serverHappy birthday for LinkChecker, I'm %d years old today!Host is emptyHostname not foundINFOInfoMissing trailing directory slash in ftp url.NOTSETNameNo MX mail host for %(domain)s found.No NNTP server was specified, skipping this URL.No newsgroup specified in NNTP URL.Output optionsParent URLPrint version and exit.Real URLResultSizeSpecify an NNTP server for 'news:...' links. Default is the environment variable NNTP_SERVER. If no host is given, only the syntax of the link is checked.Start checking at %sStatisticsStatistics:System info:That's it.URLURL is emptyURL is unrecognized or has invalid syntaxUsing proxy `%(proxy)s'.ValidWARNWARNINGWarningWrite comments and bugs to %(url)sWrite comments and bugs to %screated by %(app)s at %(time)sdirectoryempty url was givenno url was givenruntime %sshow this help message and exitProject-Id-Version: fr Report-Msgid-Bugs-To: bastian.kleineidam@web.de PO-Revision-Date: 2011-02-16 15:27+0100 Last-Translator: Bastian Kleineidam Language-Team: français Language: fr MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Generator: KBabel 1.9.1 Plural-Forms: nplurals=2; plural=(n != 1); %.3f secondes%d jour%d jours%d erreur trouvée.%d erreurs trouvées.%d heure%d heures%d lien vérifié%d liens vérifiés%d minute%d minutes%d seconde%d secondes%d avertissement trouvée.%d avertissements trouvées.%d année%d années, col. %d, ligne %dRajout d'une barre oblique terminale au répertoire.Impossible de trouver l'ancre `%(name)s'.BaseCRITICALClef du cacheAnnulé.Temps de vérificationOptions de vérificationLa taille du contenu est nulle.DEBUGNe pas afficher les messages d'état de la vérification.ERRORErreurExterneOptions généralesRécupérez la dernière version sur %(url)sRécupérez la dernière version sur %sPas de réponse du serveur FTPJoyeux anniversaire LinkChecker, j'ai %d ans aujourd'hui !L'hôte est vide.Impossible de trouver le nom d'hôteINFOInfoBarre oblique terminale manquante dans l'URL FTP.NOTSETNomAucun hôte de messagerie trouvé pour %(domain)s.Aucun serveur NNTP spécifié, l'URL est ignorée.Aucun newsgroup spécifié dans l'URL NNTP.Options de sortieURL parenteAfficher la version et quitter.URL RéelleRésultatTailleSpécifier un serveur NNTP pour les liens « news: ». Par défaut, la variable d'environnement NNTP_SERVER est utilisée. Si aucun hôte n'est donné, LinkChecker n'effectue qu'une vérification de la syntaxe du lien.Démarrage du contrôle à %sStatistiquesStatistiques :Info système :Fin.URLL'URL est vide.L'URL n'est pas reconnue ou n'a pas une syntaxe valide.Utilisation du proxy `%(proxy)s'.ValideWARNWARNINGAvertissementÉcrivez des commentaires et rapports de bogue à %(url)sÉcrivez des commentaires et rapports de bogue à %s.créé par %(app)s à %(time)srépertoireUne URL vide a été donnée.Aucune URL donnéetemps d'exécution %safficher ce message d'aide et se terminerlinkchecker-10.0.1/po/fr.po000066400000000000000000001500631400504243600154430ustar00rootroot00000000000000# 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: fr\n" "Report-Msgid-Bugs-To: bastian.kleineidam@web.de\n" "POT-Creation-Date: 2020-06-19 16:25+0100\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/configuration/confparse.py:62 #, fuzzy, python-format msgid "Error parsing configuration: %s" msgstr "Erreur : %s" #: ../linkcheck/configuration/confparse.py:69 #, python-format msgid "invalid empty value for %s: %s\n" msgstr "" #: ../linkcheck/configuration/confparse.py:83 #: ../linkcheck/plugins/sslcertcheck.py:108 #, python-format msgid "invalid value for %s: %d must not be less than %d" msgstr "" #: ../linkcheck/configuration/confparse.py:86 #, python-format msgid "invalid value for %s: %d must not be greater than %d" msgstr "" #: ../linkcheck/configuration/confparse.py:175 #, python-format msgid "missing auth part in entry %(val)r" msgstr "" #: ../linkcheck/configuration/confparse.py:181 #, python-format msgid "invalid login URL `%s'. Only HTTP and HTTPS URLs are supported." msgstr "" #: ../linkcheck/configuration/confparse.py:206 #, python-format msgid "For example execute 'chmod go-rw %s'." msgstr "" #: ../linkcheck/configuration/confparse.py:251 #, python-format msgid "See %(url)s for more info on setting file permissions." msgstr "" #: ../linkcheck/configuration/__init__.py:242 #, python-format msgid "Configuration file %r does not exist." msgstr "" #: ../linkcheck/configuration/__init__.py:244 #, python-format msgid "Configuration file %r is not readable." msgstr "" #: ../linkcheck/configuration/__init__.py:254 msgid "missing user or URL pattern in authentication data." msgstr "" #: ../linkcheck/configuration/__init__.py:293 msgid "activating text logger output." msgstr "" #: ../linkcheck/configuration/__init__.py:303 msgid "no CGI password fieldname given for login URL." msgstr "" #: ../linkcheck/configuration/__init__.py:307 msgid "no CGI user fieldname given for login URL." msgstr "" #: ../linkcheck/configuration/__init__.py:311 msgid "no user/password authentication data found for login URL." msgstr "" #: ../linkcheck/configuration/__init__.py:314 msgid "login URL is not a HTTP URL." msgstr "" #: ../linkcheck/configuration/__init__.py:318 msgid "login URL is incomplete." msgstr "" #: ../linkcheck/configuration/__init__.py:322 #, fuzzy, python-format msgid "disabling login URL %(url)s." msgstr "Erreur : %s" #: ../linkcheck/configuration/__init__.py:384 #, python-format msgid "could not create plugin directory %(dirname)r: %(errmsg)r" msgstr "" #: ../linkcheck/configuration/__init__.py:425 #, python-format msgid "" "could not copy initial configuration file %(src)r to %(dst)r: %(errmsg)r" msgstr "" #: ../linkcheck/lc_cgi.py:207 #, fuzzy, python-format msgid "unsupported language %r" msgstr "langage non accepté" #: ../linkcheck/lc_cgi.py:212 msgid "empty url was given" msgstr "Une URL vide a été donnée." #: ../linkcheck/lc_cgi.py:214 #, fuzzy, python-format msgid "disallowed url %r was given" msgstr "Une URL non autorisée a été donnée." #: ../linkcheck/lc_cgi.py:216 msgid "no url was given" msgstr "Aucune URL donnée" #: ../linkcheck/lc_cgi.py:221 #, fuzzy, python-format msgid "invalid recursion level %r" msgstr "Niveau de récursion invalide" #: ../linkcheck/lc_cgi.py:227 #, fuzzy, python-format msgid "invalid %s option %r" msgstr "option de journal %r invalide" #: ../linkcheck/lc_cgi.py:251 #, 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/__init__.py:117 msgid "CRITICAL" msgstr "CRITICAL" #: ../linkcheck/__init__.py:118 msgid "ERROR" msgstr "ERROR" #: ../linkcheck/__init__.py:119 msgid "WARN" msgstr "WARN" #: ../linkcheck/__init__.py:120 msgid "WARNING" msgstr "WARNING" #: ../linkcheck/__init__.py:121 msgid "INFO" msgstr "INFO" #: ../linkcheck/__init__.py:122 msgid "DEBUG" msgstr "DEBUG" #: ../linkcheck/__init__.py:123 msgid "NOTSET" msgstr "NOTSET" #: ../linkcheck/__init__.py:135 msgid "Running as root user; dropping privileges by changing user to nobody." msgstr "" #: ../linkcheck/cmdline.py:59 #, fuzzy, python-format msgid "Error: %(msg)s" msgstr "Erreur : %s" #: ../linkcheck/cmdline.py:60 #, fuzzy, python-format msgid "Execute '%(program)s -h' for help" msgstr "Lancez la commande « linkchecker -h » pour obtenir l'aide" #: ../linkcheck/strformat.py:247 #, python-format msgid "%(prefix)s%(duration).02f seconds" msgstr "" #: ../linkcheck/strformat.py:250 #, python-format msgid "%d second" msgid_plural "%d seconds" msgstr[0] "%d seconde" msgstr[1] "%d secondes" #: ../linkcheck/strformat.py:251 #, python-format msgid "%d minute" msgid_plural "%d minutes" msgstr[0] "%d minute" msgstr[1] "%d minutes" #: ../linkcheck/strformat.py:252 #, python-format msgid "%d hour" msgid_plural "%d hours" msgstr[0] "%d heure" msgstr[1] "%d heures" #: ../linkcheck/strformat.py:253 #, python-format msgid "%d day" msgid_plural "%d days" msgstr[0] "%d jour" msgstr[1] "%d jours" #: ../linkcheck/strformat.py:254 #, python-format msgid "%d year" msgid_plural "%d years" msgstr[0] "%d année" msgstr[1] "%d années" #: ../linkcheck/strformat.py:323 #, python-format msgid "" "Could not import %(module)s for %(feature)s. Install %(module)s from %(url)s " "to use this feature." msgstr "" #: ../linkcheck/director/aggregator.py:160 msgid "These URLs are still active:" msgstr "" #: ../linkcheck/director/aggregator.py:167 #, python-format msgid "" "%(num)d URLs are still active. After a timeout of %(timeout)s the active " "URLs will stop." msgstr "" #: ../linkcheck/director/__init__.py:35 #, fuzzy, python-format msgid "Error using login URL: %(msg)s." msgstr "Erreur : %s" #: ../linkcheck/director/__init__.py:41 #, fuzzy, python-format msgid "Error starting log output: %(msg)s." msgstr "Erreur : %s" #: ../linkcheck/director/__init__.py:56 msgid "" "Could not start a new thread. Check that the current user is allowed to " "start new threads." msgstr "" #: ../linkcheck/director/__init__.py:88 #, 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:90 msgid "another interrupt will exit immediately" msgstr "" #: ../linkcheck/director/__init__.py:106 #, fuzzy msgid "user abort; force shutdown" msgstr "interruption clavier ; en attente de la terminaison d' %d thread actif" #: ../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:41 #, 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:43 #, python-format msgid "%4d link" msgid_plural "%4d links" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:45 #, python-format msgid "%3d URL" msgid_plural "%3d URLs" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:47 #, python-format msgid "runtime %s" msgstr "temps d'exécution %s" #: ../linkcheck/director/console.py:67 #, 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:114 msgid "Default locale:" msgstr "" #: ../linkcheck/director/console.py:136 msgid "System info:" msgstr "Info système :" #: ../linkcheck/director/console.py:138 msgid "Released on:" msgstr "" #: ../linkcheck/director/console.py:139 ../linkchecker:404 #, fuzzy, python-format msgid "Python %(version)s on %(platform)s" msgstr "Python %s sur %s" #: ../linkcheck/director/console.py:145 #, fuzzy msgid "Local time:" msgstr "Temps D/L" #: ../linkcheck/director/console.py:146 msgid "sys.argv:" msgstr "" #: ../linkcheck/director/console.py:151 msgid "released" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:68 #, fuzzy msgid "valid HTML syntax" msgstr "Syntaxe mail invalide" #: ../linkcheck/plugins/syntaxchecks.py:74 #, python-format msgid "HTML syntax check plugin error: %(msg)s " msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:105 #, fuzzy msgid "valid CSS syntax" msgstr "Syntaxe mail invalide" #: ../linkcheck/plugins/syntaxchecks.py:111 #, python-format msgid "CSS syntax check plugin error: %(msg)s " msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:119 #, python-format msgid "%(w3type)s validation error at line %(line)s col %(column)s: %(msg)s" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:63 msgid "certificate did not include \"notAfter\" information" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:66 msgid "SSL verification is disabled; enable the sslverify option" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:77 #, python-format msgid "Invalid SSL certficate \"notAfter\" value %r" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:86 #, python-format msgid "SSL certficate is expired on %(expire)s." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:91 #, python-format msgid "SSL certificate expires on %(expire)s and is only %(valid)s valid." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:94 #, python-format msgid "SSL certificate expires on %(expire)s and is %(valid)s valid." msgstr "" #: ../linkcheck/plugins/anchorcheck.py:59 #, python-format msgid "Anchor `%(name)s' not found." msgstr "Impossible de trouver l'ancre `%(name)s'." #: ../linkcheck/plugins/anchorcheck.py:60 #, python-format msgid "Available anchors: %(anchors)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:162 msgid "only one of TCPSocket and LocalSocket must be enabled" msgstr "" #: ../linkcheck/plugins/viruscheck.py:191 msgid "one of TCPSocket or LocalSocket must be enabled" msgstr "" #: ../linkcheck/plugins/viruscheck.py:226 #, fuzzy msgid "Could not connect to ClamAV daemon." msgstr "Impossible de se connecter, mais la syntaxe est correcte" #: ../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/locationinfo.py:46 #, python-format msgid "URL is located in %(location)s." msgstr "" #: ../linkcheck/checker/fileurl.py:118 #, fuzzy, python-format msgid "Could not get current working directory: %(msg)s" msgstr "Impossible d'analyser le contenu : %(msg)r" #: ../linkcheck/checker/fileurl.py:152 msgid "Added trailing slash to directory." msgstr "Rajout d'une barre oblique terminale au répertoire." #: ../linkcheck/checker/fileurl.py:174 msgid "" "local files are only checked without parent URL or when the parent URL is " "also a file" msgstr "" #: ../linkcheck/checker/fileurl.py:177 msgid "directory" msgstr "répertoire" #: ../linkcheck/checker/fileurl.py:194 #, 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/ftpurl.py:91 msgid "Got no answer from FTP server" msgstr "Pas de réponse du serveur FTP" #: ../linkcheck/checker/ftpurl.py:94 #, 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:140 msgid "Missing trailing directory slash in ftp url." msgstr "Barre oblique terminale manquante dans l'URL FTP." #: ../linkcheck/checker/ftpurl.py:201 msgid "FTP file size too large" msgstr "" #: ../linkcheck/checker/mailtourl.py:84 #, fuzzy, python-format msgid "No mail addresses or email subject found in `%(url)s'." msgstr "Aucune adresse trouvée." #: ../linkcheck/checker/mailtourl.py:125 #, python-format msgid "Error parsing CGI values: %s" msgstr "" #: ../linkcheck/checker/mailtourl.py:148 #, python-format msgid "" "Mail address `%(addr)s' too long. Allowed 256 chars, was %(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:152 #, python-format msgid "Missing `@' in mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:158 #, python-format msgid "Missing local part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:162 #, python-format msgid "Missing domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:166 #, python-format msgid "" "Local part of mail address `%(addr)s' too long. Allowed 64 chars, was " "%(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:170 #, python-format msgid "" "Domain part of mail address `%(addr)s' too long. Allowed 255 chars, was " "%(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:179 #, python-format msgid "Unquoted double quote or backslash in mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:184 #, python-format msgid "Local part of mail address `%(addr)s' may not start with a dot." msgstr "" #: ../linkcheck/checker/mailtourl.py:188 #, python-format msgid "Local part of mail address `%(addr)s' may not end with a dot." msgstr "" #: ../linkcheck/checker/mailtourl.py:192 #, python-format msgid "Local part of mail address `%(addr)s' may not contain two dots." msgstr "" #: ../linkcheck/checker/mailtourl.py:197 #, python-format msgid "" "Local part of mail address `%(addr)s' contains unquoted character `%(char)s." msgstr "" #: ../linkcheck/checker/mailtourl.py:209 #, python-format msgid "Domain part of mail address `%(addr)s' has invalid IP." msgstr "" #: ../linkcheck/checker/mailtourl.py:215 #, python-format msgid "Invalid domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:219 #, python-format msgid "Invalid top level domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:252 #, 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:260 #, fuzzy, python-format msgid "No host for %(domain)s found." msgstr "Aucun hôte de messagerie trouvé pour %(domain)s." #: ../linkcheck/checker/mailtourl.py:274 #, python-format msgid "Got invalid DNS answer %(answer)s for %(domain)s." msgstr "" #: ../linkcheck/checker/mailtourl.py:286 #, fuzzy msgid "Valid mail address syntax" msgstr "Syntaxe mail invalide" #: ../linkcheck/checker/unknownurl.py:31 #, fuzzy, python-format msgid "%(scheme)s URL ignored." msgstr "URL %s ignorée." #: ../linkcheck/checker/unknownurl.py:33 #, fuzzy msgid "ignored" msgstr "URL %s ignorée." #: ../linkcheck/checker/unknownurl.py:35 msgid "URL is unrecognized or has invalid syntax" msgstr "L'URL n'est pas reconnue ou n'a pas une syntaxe valide." #: ../linkcheck/checker/const.py:102 msgid "The effective URL is different from the original." msgstr "" #: ../linkcheck/checker/const.py:104 msgid "Could not get the content of the URL." msgstr "" #: ../linkcheck/checker/const.py:105 msgid "The URL content size is too large." msgstr "" #: ../linkcheck/checker/const.py:106 msgid "The URL content size is zero." msgstr "" #: ../linkcheck/checker/const.py:107 msgid "The URL is longer than the recommended size." msgstr "" #: ../linkcheck/checker/const.py:108 msgid "The URL contains leading or trailing whitespace." msgstr "" #: ../linkcheck/checker/const.py:109 msgid "The file: URL is missing a trailing slash." msgstr "" #: ../linkcheck/checker/const.py:111 #, 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: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:115 msgid "An error occurred while storing a cookie." msgstr "" #: ../linkcheck/checker/const.py:116 #, fuzzy msgid "The URL has been ignored." msgstr "URL %s ignorée." #: ../linkcheck/checker/const.py:117 msgid "The mail MX host could not be found." msgstr "" #: ../linkcheck/checker/const.py:118 #, fuzzy msgid "No NNTP server was found." msgstr "Aucun serveur NNTP spécifié, l'URL est ignorée." #: ../linkcheck/checker/const.py:119 msgid "The NNTP newsgroup could not be found." msgstr "" #: ../linkcheck/checker/const.py:120 msgid "The IP is obfuscated." msgstr "" #: ../linkcheck/checker/const.py:121 msgid "XML could not be parsed." 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/checker/nntpurl.py:44 msgid "No NNTP server was specified, skipping this URL." msgstr "Aucun serveur NNTP spécifié, l'URL est ignorée." #: ../linkcheck/checker/nntpurl.py:54 #, fuzzy, python-format msgid "Article number %(num)s found." msgstr "Article numéro %s trouvé." #: ../linkcheck/checker/nntpurl.py:61 #, fuzzy, python-format msgid "News group %(name)s found." msgstr "Aucun hôte de messagerie trouvé pour %(domain)s." #: ../linkcheck/checker/nntpurl.py:64 msgid "No newsgroup specified in NNTP URL." msgstr "Aucun newsgroup spécifié dans l'URL NNTP." #: ../linkcheck/checker/nntpurl.py:88 #, 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." #: ../linkcheck/checker/urlbase.py:65 #, python-format msgid "URL has unparsable domain name: %(name)s" msgstr "" #: ../linkcheck/checker/urlbase.py:124 #, 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:127 msgid "filtered" msgstr "" #: ../linkcheck/checker/urlbase.py:162 #, python-format msgid "Leading or trailing whitespace in URL `%(url)s'." msgstr "" #: ../linkcheck/checker/urlbase.py:324 msgid "URL is empty" msgstr "L'URL est vide." #: ../linkcheck/checker/urlbase.py:338 #, fuzzy, python-format msgid "Effective URL %(url)r." msgstr "URL effective %r." #: ../linkcheck/checker/urlbase.py:344 #, 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:390 #, fuzzy, python-format msgid "URL host %(host)r has invalid port" msgstr "Le port %r de l'URL est invalide." #: ../linkcheck/checker/urlbase.py:397 #, fuzzy msgid "URL has empty hostname" msgstr "L'URL est vide." #: ../linkcheck/checker/urlbase.py:421 #, python-format msgid "URL %(url)s has obfuscated IP address %(ip)s" msgstr "" #: ../linkcheck/checker/urlbase.py:456 msgid "Hostname not found" msgstr "Impossible de trouver le nom d'hôte" #: ../linkcheck/checker/urlbase.py:459 #, python-format msgid "Bad hostname %(host)r: %(msg)s" msgstr "" #: ../linkcheck/checker/urlbase.py:475 #, fuzzy, python-format msgid "could not get content: %(msg)s" msgstr "Impossible d'analyser le contenu : %(msg)r" #: ../linkcheck/checker/urlbase.py:526 #, 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:619 msgid "Content size is zero." msgstr "La taille du contenu est nulle." #: ../linkcheck/checker/urlbase.py:649 ../linkcheck/checker/httpurl.py:313 msgid "File size too large" msgstr "" #: ../linkcheck/checker/urlbase.py:717 #, python-format msgid "URL has unparsable domain name: %(domain)s" msgstr "" #: ../linkcheck/checker/proxysupport.py:43 #, python-format msgid "Proxy value `%(proxy)s' must start with 'http:' or 'https:'." msgstr "" #: ../linkcheck/checker/proxysupport.py:49 #, python-format msgid "Ignoring proxy setting `%(proxy)s'." msgstr "" #: ../linkcheck/checker/proxysupport.py:54 #, python-format msgid "Using proxy `%(proxy)s'." msgstr "Utilisation du proxy `%(proxy)s'." #: ../linkcheck/checker/itmsservicesurl.py:32 msgid "Missing required url parameter" msgstr "" #: ../linkcheck/checker/telneturl.py:52 msgid "Host is empty" msgstr "L'hôte est vide." #: ../linkcheck/checker/httpurl.py:125 #, 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:126 msgid "syntax OK" msgstr "" #: ../linkcheck/checker/httpurl.py:257 #, fuzzy, python-format msgid "Redirected to `%(url)s'." msgstr "Redirigé vers %(url)s." #: ../linkcheck/checker/httpurl.py:297 msgid "OK" msgstr "" #: ../linkcheck/logger/text.py:98 ../linkcheck/logger/__init__.py:380 #, python-format msgid "Get the newest version at %(url)s" msgstr "Récupérez la dernière version sur %(url)s" #: ../linkcheck/logger/text.py:100 ../linkcheck/logger/__init__.py:382 #, python-format msgid "Write comments and bugs to %(url)s" msgstr "Écrivez des commentaires et rapports de bogue à %(url)s" #: ../linkcheck/logger/text.py:104 ../linkcheck/logger/html.py:122 #, python-format msgid "Start checking at %s" msgstr "Démarrage du contrôle à %s" #: ../linkcheck/logger/text.py:158 ../linkcheck/logger/html.py:192 #, python-format msgid ", line %d" msgstr ", ligne %d" #: ../linkcheck/logger/text.py:160 ../linkcheck/logger/html.py:194 #, python-format msgid ", col %d" msgstr ", col. %d" #: ../linkcheck/logger/text.py:162 ../linkcheck/logger/html.py:196 #, fuzzy, python-format msgid ", page %d" msgstr ", ligne %d" #: ../linkcheck/logger/text.py:178 ../linkcheck/logger/text.py:190 #: ../linkcheck/logger/html.py:220 ../linkcheck/logger/html.py:232 #, python-format msgid "%.3f seconds" msgstr "%.3f secondes" #: ../linkcheck/logger/text.py:214 ../linkcheck/logger/html.py:261 msgid "Valid" msgstr "Valide" #: ../linkcheck/logger/text.py:217 ../linkcheck/logger/html.py:266 msgid "Error" msgstr "Erreur" #: ../linkcheck/logger/text.py:226 msgid "The check has been interrupted; results are not complete." msgstr "" #: ../linkcheck/logger/text.py:227 ../linkcheck/logger/html.py:291 msgid "That's it." msgstr "Fin." #: ../linkcheck/logger/text.py:228 #, 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:232 #, fuzzy, python-format msgid "in %d URL" msgid_plural "in %d URLs" msgstr[0] "URLs valides" msgstr[1] "URLs valides" #: ../linkcheck/logger/text.py:235 ../linkcheck/logger/html.py:296 #, 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/text.py:243 ../linkcheck/logger/html.py:299 #, python-format msgid " (%d ignored or duplicates not printed)" msgstr "" #: ../linkcheck/logger/text.py:246 ../linkcheck/logger/html.py:302 #, 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/text.py:254 ../linkcheck/logger/html.py:305 #, python-format msgid " (%d duplicates not printed)" msgstr "" #: ../linkcheck/logger/text.py:259 ../linkcheck/logger/html.py:311 #, python-format msgid "There was %(num)d internal error." msgid_plural "There were %(num)d internal errors." msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/text.py:263 ../linkcheck/logger/__init__.py:390 #: ../linkcheck/logger/html.py:316 #, fuzzy, python-format msgid "Stopped checking at %(time)s (%(duration)s)" msgstr "Arrêt du contrôle à %s (%s)" #: ../linkcheck/logger/text.py:270 msgid "Statistics:" msgstr "Statistiques :" #: ../linkcheck/logger/text.py:272 #, python-format msgid "Downloaded: %s." msgstr "" #: ../linkcheck/logger/text.py:275 ../linkcheck/logger/html.py:276 #, 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/text.py:278 ../linkcheck/logger/html.py:280 #, python-format msgid "URL lengths: min=%(min)d, max=%(max)d, avg=%(avg)d." msgstr "" #: ../linkcheck/logger/text.py:283 ../linkcheck/logger/html.py:285 #, 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/__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:278 #, 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:377 #, python-format msgid "created by %(app)s at %(time)s" msgstr "créé par %(app)s à %(time)s" #: ../linkcheck/logger/html.py:273 msgid "Statistics" msgstr "Statistiques" #: ../linkcheck/logger/html.py:293 #, 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:321 #, python-format msgid "Get the newest version at %s" msgstr "Récupérez la dernière version sur %s" #: ../linkcheck/logger/html.py:324 #, python-format msgid "Write comments and bugs to %s" msgstr "Écrivez des commentaires et rapports de bogue à %s." #: ../linkchecker:55 #, 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" " o When checking 'news:' links the given NNTP host doesn't need to be the\n" " same as the host of the user browsing your pages.\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" #: ../linkchecker:71 msgid "" "PROXY SUPPORT\n" "To use a proxy on Unix or Windows set $http_proxy, $https_proxy or " "$ftp_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, and gconf or KDE on Linux systems.\n" "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 "" #: ../linkchecker:96 msgid "" "REGULAR EXPRESSIONS\n" "Only Python regular expressions are accepted by LinkChecker.\n" "See http://www.amk.ca/python/howto/regex/ 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 "" #: ../linkchecker:105 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 "" #: ../linkchecker:133 #, 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" #: ../linkchecker:140 #, 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" #: ../linkchecker:164 #, 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" "blacklist\n" " Suitable for cron jobs. Logs the check result into a file\n" " ~/.linkchecker/blacklist which only contains entries with invalid\n" " 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" #: ../linkchecker:189 msgid "" "IGNORE WARNINGS\n" "The following warnings are recognized in the 'ignorewarnings' config\n" "file entry:\n" msgstr "" #: ../linkchecker:219 msgid "General options" msgstr "Options générales" #: ../linkchecker:223 #, fuzzy, python-format msgid "" "Use FILENAME as configuration file. Per default LinkChecker uses\n" "~/.linkchecker/linkcheckerrc (under Windows\n" "%%HOMEPATH%%\\.linkchecker\\linkcheckerrc)." msgstr "" "Utiliser CONFIGFILE comme fichier de configuration. LinkChecker\n" "recherche d'abord /etc/linkchecker/linkcheckerrc puis ~/.linkchecker/" "linkcheckerrc\n" "(sous Windows \\linkcheckerrc)." #: ../linkchecker:228 #, 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." #: ../linkchecker:231 msgid "Print version and exit." msgstr "Afficher la version et quitter." #: ../linkchecker:234 #, fuzzy msgid "Print available check plugins and exit." msgstr "Afficher la version et quitter." #: ../linkchecker:237 msgid "Read list of white-space separated URLs to check from stdin." msgstr "" #: ../linkchecker:240 msgid "Output options" msgstr "Options de sortie" #: ../linkchecker:251 #, 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." #: ../linkchecker:262 #, fuzzy, python-format msgid "" "Output to a file linkchecker-out.TYPE, $HOME/.linkchecker/blacklist for\n" "'blacklist' 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 http://docs.python.org/lib/standard-encodings." "html.\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'." #: ../linkchecker:276 msgid "Do not print check status messages." msgstr "Ne pas afficher les messages d'état de la vérification." #: ../linkchecker:278 msgid "Don't log warnings. Default is to log warnings." msgstr "" #: ../linkchecker:281 #, 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 http://docs.python.org/lib/standard-encodings." "html." 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." #: ../linkchecker:291 #, fuzzy msgid "" "Quiet operation, an alias for '-o none'.\n" "This is only useful with -F." msgstr "Exécution silencieuse. Utile seulement avec -F." #: ../linkchecker:300 #, 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." #: ../linkchecker:312 msgid "Checking options" msgstr "Options de vérification" #: ../linkchecker:321 msgid "" "Read a file with initial cookie data. The cookie data format is\n" "explained below." msgstr "" #: ../linkchecker:325 msgid "Disable robots.txt checks" msgstr "" #: ../linkchecker:327 msgid "Check external URLs." msgstr "" #: ../linkchecker:330 msgid "" "Only check syntax of URLs matching the given regular expression.\n" " This option can be given multiple times." msgstr "" #: ../linkchecker:334 msgid "" "Check but do not recurse into URLs matching the given regular\n" "expression. This option can be given multiple times." msgstr "" #: ../linkchecker:338 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." #: ../linkchecker:344 #, 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." #: ../linkchecker:354 #, 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." #: ../linkchecker:359 #, fuzzy, python-format msgid "" "Set the timeout for connection attempts in seconds. The default\n" "timeout is %d 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." #: ../linkchecker:363 #, 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." #: ../linkchecker:368 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 "" #: ../linkchecker:402 #, python-format msgid "Invalid debug level %(level)r" msgstr "" #: ../linkchecker:415 #, python-format msgid "Unreadable config file: %r" msgstr "" #: ../linkchecker:423 msgid "Running with python -O disables debugging." msgstr "" #: ../linkchecker:453 ../linkchecker:485 #, 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" #: ../linkchecker:457 ../linkchecker:491 #, 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" #: ../linkchecker:503 #, python-format msgid "Enter LinkChecker HTTP/FTP password for user %(user)s:" msgstr "" #: ../linkchecker:506 msgid "Enter LinkChecker HTTP/FTP password:" msgstr "" #: ../linkchecker:525 #, fuzzy, python-format msgid "Illegal argument %(arg)r for option %(option)s" msgstr "Argument %r illégal pour l'option %s" #: ../linkchecker:542 #, python-format msgid "Enter LinkChecker password for user %(user)s at %(strpattern)s:" msgstr "" #: ../linkchecker:551 #, fuzzy, python-format msgid "Could not read cookie file %s" msgstr "Impossible d'enregistrer les cookies : %(msg)s." #: ../linkchecker:576 #, fuzzy msgid "no files or URLs given" msgstr "aucun fichier ou URL donné" #: ../linkchecker:581 #, 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." #: ../linkchecker:586 msgid "Canceled." msgstr "Annulé." #: ../linkchecker:590 msgid "" "The `yappi' Python module is not installed, therefore the --profile option " "is disabled." msgstr "" #: ../linkchecker:606 msgid "Dumping memory statistics..." msgstr "" #: ../linkchecker:608 #, python-format msgid "The memory dump has been written to `%(filename)s'." msgstr "" #: /usr/lib/python3.8/argparse.py:295 #, fuzzy msgid "usage: " msgstr "Usage : %s\n" #: /usr/lib/python3.8/argparse.py:846 msgid ".__call__() not defined" msgstr "" #: /usr/lib/python3.8/argparse.py:1149 #, python-format msgid "unknown parser %(parser_name)r (choices: %(choices)s)" msgstr "" #: /usr/lib/python3.8/argparse.py:1209 #, python-format msgid "argument \"-\" with mode %r" msgstr "" #: /usr/lib/python3.8/argparse.py:1218 #, python-format msgid "can't open '%(filename)s': %(error)s" msgstr "" #: /usr/lib/python3.8/argparse.py:1427 #, python-format msgid "cannot merge actions - two groups are named %r" msgstr "" #: /usr/lib/python3.8/argparse.py:1465 msgid "'required' is an invalid argument for positionals" msgstr "" #: /usr/lib/python3.8/argparse.py:1487 #, python-format msgid "" "invalid option string %(option)r: must start with a character " "%(prefix_chars)r" msgstr "" #: /usr/lib/python3.8/argparse.py:1507 #, python-format msgid "dest= is required for options like %r" msgstr "" #: /usr/lib/python3.8/argparse.py:1524 #, python-format msgid "invalid conflict_resolution value: %r" msgstr "" #: /usr/lib/python3.8/argparse.py:1542 #, fuzzy, python-format msgid "conflicting option string: %s" msgid_plural "conflicting option strings: %s" msgstr[0] "Options obsolètes" msgstr[1] "Options obsolètes" #: /usr/lib/python3.8/argparse.py:1608 msgid "mutually exclusive arguments must be optional" msgstr "" #: /usr/lib/python3.8/argparse.py:1671 #, fuzzy msgid "positional arguments" msgstr "L'option %s nécessite un argument" #: /usr/lib/python3.8/argparse.py:1672 #, fuzzy msgid "optional arguments" msgstr "L'option %s nécessite un argument" #: /usr/lib/python3.8/argparse.py:1687 msgid "show this help message and exit" msgstr "afficher ce message d'aide et se terminer" #: /usr/lib/python3.8/argparse.py:1718 msgid "cannot have multiple subparser arguments" msgstr "" #: /usr/lib/python3.8/argparse.py:1770 /usr/lib/python3.8/argparse.py:2277 #, python-format msgid "unrecognized arguments: %s" msgstr "" #: /usr/lib/python3.8/argparse.py:1867 #, python-format msgid "not allowed with argument %s" msgstr "" #: /usr/lib/python3.8/argparse.py:1913 /usr/lib/python3.8/argparse.py:1927 #, python-format msgid "ignored explicit argument %r" msgstr "" #: /usr/lib/python3.8/argparse.py:2034 #, python-format msgid "the following arguments are required: %s" msgstr "" #: /usr/lib/python3.8/argparse.py:2049 #, python-format msgid "one of the arguments %s is required" msgstr "" #: /usr/lib/python3.8/argparse.py:2092 msgid "expected one argument" msgstr "" #: /usr/lib/python3.8/argparse.py:2093 msgid "expected at most one argument" msgstr "" #: /usr/lib/python3.8/argparse.py:2094 msgid "expected at least one argument" msgstr "" #: /usr/lib/python3.8/argparse.py:2098 #, python-format msgid "expected %s argument" msgid_plural "expected %s arguments" msgstr[0] "" msgstr[1] "" #: /usr/lib/python3.8/argparse.py:2156 #, fuzzy, python-format msgid "ambiguous option: %(option)s could match %(matches)s" msgstr "option ambiguë : %s (%s ?)" #: /usr/lib/python3.8/argparse.py:2220 #, fuzzy, python-format msgid "unexpected option string: %s" msgstr "Options obsolètes" #: /usr/lib/python3.8/argparse.py:2417 #, python-format msgid "%r is not callable" msgstr "" #: /usr/lib/python3.8/argparse.py:2434 #, fuzzy, python-format msgid "invalid %(type)s value: %(value)r" msgstr "option %s : valeur %s invalide : %r" #: /usr/lib/python3.8/argparse.py:2445 #, fuzzy, python-format msgid "invalid choice: %(value)r (choose from %(choices)s)" msgstr "option %s : choix invalide : %r (choisir dans %s)" #: /usr/lib/python3.8/argparse.py:2521 #, fuzzy, python-format msgid "%(prog)s: error: %(message)s\n" msgstr "extern%d : erreur de syntaxe %s\n" #~ msgid "show program's version number and exit" #~ msgstr "afficher le numéro de version du programme et se terminer" linkchecker-10.0.1/po/linkchecker.pot000066400000000000000000001157771400504243600175170ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Bastian Kleineidam # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: bastian.kleineidam@web.de\n" "POT-Creation-Date: 2020-06-19 16:25+0100\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/configuration/confparse.py:62 #, python-format msgid "Error parsing configuration: %s" msgstr "" #: ../linkcheck/configuration/confparse.py:69 #, python-format msgid "invalid empty value for %s: %s\n" msgstr "" #: ../linkcheck/configuration/confparse.py:83 #: ../linkcheck/plugins/sslcertcheck.py:108 #, python-format msgid "invalid value for %s: %d must not be less than %d" msgstr "" #: ../linkcheck/configuration/confparse.py:86 #, python-format msgid "invalid value for %s: %d must not be greater than %d" msgstr "" #: ../linkcheck/configuration/confparse.py:175 #, python-format msgid "missing auth part in entry %(val)r" msgstr "" #: ../linkcheck/configuration/confparse.py:181 #, python-format msgid "invalid login URL `%s'. Only HTTP and HTTPS URLs are supported." msgstr "" #: ../linkcheck/configuration/confparse.py:206 #, python-format msgid "For example execute 'chmod go-rw %s'." msgstr "" #: ../linkcheck/configuration/confparse.py:251 #, python-format msgid "See %(url)s for more info on setting file permissions." msgstr "" #: ../linkcheck/configuration/__init__.py:242 #, python-format msgid "Configuration file %r does not exist." msgstr "" #: ../linkcheck/configuration/__init__.py:244 #, python-format msgid "Configuration file %r is not readable." msgstr "" #: ../linkcheck/configuration/__init__.py:254 msgid "missing user or URL pattern in authentication data." msgstr "" #: ../linkcheck/configuration/__init__.py:293 msgid "activating text logger output." msgstr "" #: ../linkcheck/configuration/__init__.py:303 msgid "no CGI password fieldname given for login URL." msgstr "" #: ../linkcheck/configuration/__init__.py:307 msgid "no CGI user fieldname given for login URL." msgstr "" #: ../linkcheck/configuration/__init__.py:311 msgid "no user/password authentication data found for login URL." msgstr "" #: ../linkcheck/configuration/__init__.py:314 msgid "login URL is not a HTTP URL." msgstr "" #: ../linkcheck/configuration/__init__.py:318 msgid "login URL is incomplete." msgstr "" #: ../linkcheck/configuration/__init__.py:322 #, python-format msgid "disabling login URL %(url)s." msgstr "" #: ../linkcheck/configuration/__init__.py:384 #, python-format msgid "could not create plugin directory %(dirname)r: %(errmsg)r" msgstr "" #: ../linkcheck/configuration/__init__.py:425 #, python-format msgid "could not copy initial configuration file %(src)r to %(dst)r: %(errmsg)r" msgstr "" #: ../linkcheck/lc_cgi.py:207 #, python-format msgid "unsupported language %r" msgstr "" #: ../linkcheck/lc_cgi.py:212 msgid "empty url was given" msgstr "" #: ../linkcheck/lc_cgi.py:214 #, python-format msgid "disallowed url %r was given" msgstr "" #: ../linkcheck/lc_cgi.py:216 msgid "no url was given" msgstr "" #: ../linkcheck/lc_cgi.py:221 #, python-format msgid "invalid recursion level %r" msgstr "" #: ../linkcheck/lc_cgi.py:227 #, python-format msgid "invalid %s option %r" msgstr "" #: ../linkcheck/lc_cgi.py:251 #, 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/__init__.py:117 msgid "CRITICAL" msgstr "" #: ../linkcheck/__init__.py:118 msgid "ERROR" msgstr "" #: ../linkcheck/__init__.py:119 msgid "WARN" msgstr "" #: ../linkcheck/__init__.py:120 msgid "WARNING" msgstr "" #: ../linkcheck/__init__.py:121 msgid "INFO" msgstr "" #: ../linkcheck/__init__.py:122 msgid "DEBUG" msgstr "" #: ../linkcheck/__init__.py:123 msgid "NOTSET" msgstr "" #: ../linkcheck/__init__.py:135 msgid "Running as root user; dropping privileges by changing user to nobody." msgstr "" #: ../linkcheck/cmdline.py:59 #, python-format msgid "Error: %(msg)s" msgstr "" #: ../linkcheck/cmdline.py:60 #, python-format msgid "Execute '%(program)s -h' for help" msgstr "" #: ../linkcheck/strformat.py:247 #, python-format msgid "%(prefix)s%(duration).02f seconds" msgstr "" #: ../linkcheck/strformat.py:250 #, python-format msgid "%d second" msgid_plural "%d seconds" msgstr[0] "" msgstr[1] "" #: ../linkcheck/strformat.py:251 #, python-format msgid "%d minute" msgid_plural "%d minutes" msgstr[0] "" msgstr[1] "" #: ../linkcheck/strformat.py:252 #, python-format msgid "%d hour" msgid_plural "%d hours" msgstr[0] "" msgstr[1] "" #: ../linkcheck/strformat.py:253 #, python-format msgid "%d day" msgid_plural "%d days" msgstr[0] "" msgstr[1] "" #: ../linkcheck/strformat.py:254 #, python-format msgid "%d year" msgid_plural "%d years" msgstr[0] "" msgstr[1] "" #: ../linkcheck/strformat.py:323 #, python-format msgid "" "Could not import %(module)s for %(feature)s. Install %(module)s from %(url)s " "to use this feature." msgstr "" #: ../linkcheck/director/aggregator.py:160 msgid "These URLs are still active:" msgstr "" #: ../linkcheck/director/aggregator.py:167 #, python-format msgid "" "%(num)d URLs are still active. After a timeout of %(timeout)s the active URLs " "will stop." msgstr "" #: ../linkcheck/director/__init__.py:35 #, python-format msgid "Error using login URL: %(msg)s." msgstr "" #: ../linkcheck/director/__init__.py:41 #, python-format msgid "Error starting log output: %(msg)s." msgstr "" #: ../linkcheck/director/__init__.py:56 msgid "" "Could not start a new thread. Check that the current user is allowed to start " "new threads." msgstr "" #: ../linkcheck/director/__init__.py:88 msgid "interrupt; waiting for active threads to finish" msgstr "" #: ../linkcheck/director/__init__.py:90 msgid "another interrupt will exit immediately" msgstr "" #: ../linkcheck/director/__init__.py:106 msgid "user abort; force shutdown" 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:41 #, python-format msgid "%5d link queued" msgid_plural "%5d links queued" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:43 #, python-format msgid "%4d link" msgid_plural "%4d links" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:45 #, python-format msgid "%3d URL" msgid_plural "%3d URLs" msgstr[0] "" msgstr[1] "" #: ../linkcheck/director/console.py:47 #, python-format msgid "runtime %s" msgstr "" #: ../linkcheck/director/console.py:67 #, 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:114 msgid "Default locale:" msgstr "" #: ../linkcheck/director/console.py:136 msgid "System info:" msgstr "" #: ../linkcheck/director/console.py:138 msgid "Released on:" msgstr "" #: ../linkcheck/director/console.py:139 ../linkchecker:404 #, python-format msgid "Python %(version)s on %(platform)s" msgstr "" #: ../linkcheck/director/console.py:145 msgid "Local time:" msgstr "" #: ../linkcheck/director/console.py:146 msgid "sys.argv:" msgstr "" #: ../linkcheck/director/console.py:151 msgid "released" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:68 msgid "valid HTML syntax" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:74 #, python-format msgid "HTML syntax check plugin error: %(msg)s " msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:105 msgid "valid CSS syntax" msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:111 #, python-format msgid "CSS syntax check plugin error: %(msg)s " msgstr "" #: ../linkcheck/plugins/syntaxchecks.py:119 #, python-format msgid "%(w3type)s validation error at line %(line)s col %(column)s: %(msg)s" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:63 msgid "certificate did not include \"notAfter\" information" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:66 msgid "SSL verification is disabled; enable the sslverify option" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:77 #, python-format msgid "Invalid SSL certficate \"notAfter\" value %r" msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:86 #, python-format msgid "SSL certficate is expired on %(expire)s." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:91 #, python-format msgid "SSL certificate expires on %(expire)s and is only %(valid)s valid." msgstr "" #: ../linkcheck/plugins/sslcertcheck.py:94 #, python-format msgid "SSL certificate expires on %(expire)s and is %(valid)s valid." msgstr "" #: ../linkcheck/plugins/anchorcheck.py:59 #, python-format msgid "Anchor `%(name)s' not found." msgstr "" #: ../linkcheck/plugins/anchorcheck.py:60 #, python-format msgid "Available anchors: %(anchors)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:162 msgid "only one of TCPSocket and LocalSocket must be enabled" msgstr "" #: ../linkcheck/plugins/viruscheck.py:191 msgid "one of TCPSocket or LocalSocket must be enabled" msgstr "" #: ../linkcheck/plugins/viruscheck.py:226 msgid "Could not connect to ClamAV daemon." msgstr "" #: ../linkcheck/plugins/regexcheck.py:61 #, python-format msgid "Found %(match)r at line %(line)d in link contents." msgstr "" #: ../linkcheck/plugins/locationinfo.py:46 #, python-format msgid "URL is located in %(location)s." msgstr "" #: ../linkcheck/checker/fileurl.py:118 #, python-format msgid "Could not get current working directory: %(msg)s" msgstr "" #: ../linkcheck/checker/fileurl.py:152 msgid "Added trailing slash to directory." msgstr "" #: ../linkcheck/checker/fileurl.py:174 msgid "" "local files are only checked without parent URL or when the parent URL is " "also a file" msgstr "" #: ../linkcheck/checker/fileurl.py:177 msgid "directory" msgstr "" #: ../linkcheck/checker/fileurl.py:194 #, 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/ftpurl.py:91 msgid "Got no answer from FTP server" msgstr "" #: ../linkcheck/checker/ftpurl.py:94 #, python-format msgid "Remote host has closed connection: %(msg)s" msgstr "" #: ../linkcheck/checker/ftpurl.py:140 msgid "Missing trailing directory slash in ftp url." msgstr "" #: ../linkcheck/checker/ftpurl.py:201 msgid "FTP file size too large" msgstr "" #: ../linkcheck/checker/mailtourl.py:84 #, python-format msgid "No mail addresses or email subject found in `%(url)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:125 #, python-format msgid "Error parsing CGI values: %s" msgstr "" #: ../linkcheck/checker/mailtourl.py:148 #, python-format msgid "" "Mail address `%(addr)s' too long. Allowed 256 chars, was %(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:152 #, python-format msgid "Missing `@' in mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:158 #, python-format msgid "Missing local part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:162 #, python-format msgid "Missing domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:166 #, python-format msgid "" "Local part of mail address `%(addr)s' too long. Allowed 64 chars, was " "%(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:170 #, python-format msgid "" "Domain part of mail address `%(addr)s' too long. Allowed 255 chars, was " "%(length)d chars." msgstr "" #: ../linkcheck/checker/mailtourl.py:179 #, python-format msgid "Unquoted double quote or backslash in mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:184 #, python-format msgid "Local part of mail address `%(addr)s' may not start with a dot." msgstr "" #: ../linkcheck/checker/mailtourl.py:188 #, python-format msgid "Local part of mail address `%(addr)s' may not end with a dot." msgstr "" #: ../linkcheck/checker/mailtourl.py:192 #, python-format msgid "Local part of mail address `%(addr)s' may not contain two dots." msgstr "" #: ../linkcheck/checker/mailtourl.py:197 #, python-format msgid "" "Local part of mail address `%(addr)s' contains unquoted character `%(char)s." msgstr "" #: ../linkcheck/checker/mailtourl.py:209 #, python-format msgid "Domain part of mail address `%(addr)s' has invalid IP." msgstr "" #: ../linkcheck/checker/mailtourl.py:215 #, python-format msgid "Invalid domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:219 #, python-format msgid "Invalid top level domain part of mail address `%(addr)s'." msgstr "" #: ../linkcheck/checker/mailtourl.py:252 #, python-format msgid "No MX mail host for %(domain)s found." msgstr "" #: ../linkcheck/checker/mailtourl.py:260 #, python-format msgid "No host for %(domain)s found." msgstr "" #: ../linkcheck/checker/mailtourl.py:274 #, python-format msgid "Got invalid DNS answer %(answer)s for %(domain)s." msgstr "" #: ../linkcheck/checker/mailtourl.py:286 msgid "Valid mail address syntax" msgstr "" #: ../linkcheck/checker/unknownurl.py:31 #, python-format msgid "%(scheme)s URL ignored." msgstr "" #: ../linkcheck/checker/unknownurl.py:33 msgid "ignored" msgstr "" #: ../linkcheck/checker/unknownurl.py:35 msgid "URL is unrecognized or has invalid syntax" msgstr "" #: ../linkcheck/checker/const.py:102 msgid "The effective URL is different from the original." msgstr "" #: ../linkcheck/checker/const.py:104 msgid "Could not get the content of the URL." msgstr "" #: ../linkcheck/checker/const.py:105 msgid "The URL content size is too large." msgstr "" #: ../linkcheck/checker/const.py:106 msgid "The URL content size is zero." msgstr "" #: ../linkcheck/checker/const.py:107 msgid "The URL is longer than the recommended size." msgstr "" #: ../linkcheck/checker/const.py:108 msgid "The URL contains leading or trailing whitespace." msgstr "" #: ../linkcheck/checker/const.py:109 msgid "The file: URL is missing a trailing slash." msgstr "" #: ../linkcheck/checker/const.py:111 msgid "The file: path is not the same as the system specific path." 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:115 msgid "An error occurred while storing a cookie." msgstr "" #: ../linkcheck/checker/const.py:116 msgid "The URL has been ignored." msgstr "" #: ../linkcheck/checker/const.py:117 msgid "The mail MX host could not be found." msgstr "" #: ../linkcheck/checker/const.py:118 msgid "No NNTP server was found." msgstr "" #: ../linkcheck/checker/const.py:119 msgid "The NNTP newsgroup could not be found." msgstr "" #: ../linkcheck/checker/const.py:120 msgid "The IP is obfuscated." msgstr "" #: ../linkcheck/checker/const.py:121 msgid "XML could not be parsed." 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/checker/nntpurl.py:44 msgid "No NNTP server was specified, skipping this URL." msgstr "" #: ../linkcheck/checker/nntpurl.py:54 #, python-format msgid "Article number %(num)s found." msgstr "" #: ../linkcheck/checker/nntpurl.py:61 #, python-format msgid "News group %(name)s found." msgstr "" #: ../linkcheck/checker/nntpurl.py:64 msgid "No newsgroup specified in NNTP URL." msgstr "" #: ../linkcheck/checker/nntpurl.py:88 #, python-format msgid "NNTP server too busy; tried more than %d times." msgstr "" #: ../linkcheck/checker/urlbase.py:65 #, python-format msgid "URL has unparsable domain name: %(name)s" msgstr "" #: ../linkcheck/checker/urlbase.py:124 msgid "The URL is outside of the domain filter, checked only syntax." msgstr "" #: ../linkcheck/checker/urlbase.py:127 msgid "filtered" msgstr "" #: ../linkcheck/checker/urlbase.py:162 #, python-format msgid "Leading or trailing whitespace in URL `%(url)s'." msgstr "" #: ../linkcheck/checker/urlbase.py:324 msgid "URL is empty" msgstr "" #: ../linkcheck/checker/urlbase.py:338 #, python-format msgid "Effective URL %(url)r." msgstr "" #: ../linkcheck/checker/urlbase.py:344 #, python-format msgid "URL length %(len)d is longer than %(max)d." msgstr "" #: ../linkcheck/checker/urlbase.py:390 #, python-format msgid "URL host %(host)r has invalid port" msgstr "" #: ../linkcheck/checker/urlbase.py:397 msgid "URL has empty hostname" msgstr "" #: ../linkcheck/checker/urlbase.py:421 #, python-format msgid "URL %(url)s has obfuscated IP address %(ip)s" msgstr "" #: ../linkcheck/checker/urlbase.py:456 msgid "Hostname not found" msgstr "" #: ../linkcheck/checker/urlbase.py:459 #, python-format msgid "Bad hostname %(host)r: %(msg)s" msgstr "" #: ../linkcheck/checker/urlbase.py:475 #, python-format msgid "could not get content: %(msg)s" msgstr "" #: ../linkcheck/checker/urlbase.py:526 #, python-format msgid "Content size %(size)s is larger than %(maxbytes)s." msgstr "" #: ../linkcheck/checker/urlbase.py:619 msgid "Content size is zero." msgstr "" #: ../linkcheck/checker/urlbase.py:649 ../linkcheck/checker/httpurl.py:313 msgid "File size too large" msgstr "" #: ../linkcheck/checker/urlbase.py:717 #, python-format msgid "URL has unparsable domain name: %(domain)s" msgstr "" #: ../linkcheck/checker/proxysupport.py:43 #, python-format msgid "Proxy value `%(proxy)s' must start with 'http:' or 'https:'." msgstr "" #: ../linkcheck/checker/proxysupport.py:49 #, python-format msgid "Ignoring proxy setting `%(proxy)s'." msgstr "" #: ../linkcheck/checker/proxysupport.py:54 #, python-format msgid "Using proxy `%(proxy)s'." msgstr "" #: ../linkcheck/checker/itmsservicesurl.py:32 msgid "Missing required url parameter" msgstr "" #: ../linkcheck/checker/telneturl.py:52 msgid "Host is empty" msgstr "" #: ../linkcheck/checker/httpurl.py:125 msgid "Access denied by robots.txt, checked only syntax." msgstr "" #: ../linkcheck/checker/httpurl.py:126 msgid "syntax OK" msgstr "" #: ../linkcheck/checker/httpurl.py:257 #, python-format msgid "Redirected to `%(url)s'." msgstr "" #: ../linkcheck/checker/httpurl.py:297 msgid "OK" msgstr "" #: ../linkcheck/logger/text.py:98 ../linkcheck/logger/__init__.py:380 #, python-format msgid "Get the newest version at %(url)s" msgstr "" #: ../linkcheck/logger/text.py:100 ../linkcheck/logger/__init__.py:382 #, python-format msgid "Write comments and bugs to %(url)s" msgstr "" #: ../linkcheck/logger/text.py:104 ../linkcheck/logger/html.py:122 #, python-format msgid "Start checking at %s" msgstr "" #: ../linkcheck/logger/text.py:158 ../linkcheck/logger/html.py:192 #, python-format msgid ", line %d" msgstr "" #: ../linkcheck/logger/text.py:160 ../linkcheck/logger/html.py:194 #, python-format msgid ", col %d" msgstr "" #: ../linkcheck/logger/text.py:162 ../linkcheck/logger/html.py:196 #, python-format msgid ", page %d" msgstr "" #: ../linkcheck/logger/text.py:178 ../linkcheck/logger/text.py:190 #: ../linkcheck/logger/html.py:220 ../linkcheck/logger/html.py:232 #, python-format msgid "%.3f seconds" msgstr "" #: ../linkcheck/logger/text.py:214 ../linkcheck/logger/html.py:261 msgid "Valid" msgstr "" #: ../linkcheck/logger/text.py:217 ../linkcheck/logger/html.py:266 msgid "Error" msgstr "" #: ../linkcheck/logger/text.py:226 msgid "The check has been interrupted; results are not complete." msgstr "" #: ../linkcheck/logger/text.py:227 ../linkcheck/logger/html.py:291 msgid "That's it." msgstr "" #: ../linkcheck/logger/text.py:228 #, python-format msgid "%d link" msgid_plural "%d links" msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/text.py:232 #, python-format msgid "in %d URL" msgid_plural "in %d URLs" msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/text.py:235 ../linkcheck/logger/html.py:296 #, python-format msgid "%d warning found" msgid_plural "%d warnings found" msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/text.py:243 ../linkcheck/logger/html.py:299 #, python-format msgid " (%d ignored or duplicates not printed)" msgstr "" #: ../linkcheck/logger/text.py:246 ../linkcheck/logger/html.py:302 #, python-format msgid "%d error found" msgid_plural "%d errors found" msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/text.py:254 ../linkcheck/logger/html.py:305 #, python-format msgid " (%d duplicates not printed)" msgstr "" #: ../linkcheck/logger/text.py:259 ../linkcheck/logger/html.py:311 #, python-format msgid "There was %(num)d internal error." msgid_plural "There were %(num)d internal errors." msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/text.py:263 ../linkcheck/logger/__init__.py:390 #: ../linkcheck/logger/html.py:316 #, python-format msgid "Stopped checking at %(time)s (%(duration)s)" msgstr "" #: ../linkcheck/logger/text.py:270 msgid "Statistics:" msgstr "" #: ../linkcheck/logger/text.py:272 #, python-format msgid "Downloaded: %s." msgstr "" #: ../linkcheck/logger/text.py:275 ../linkcheck/logger/html.py:276 #, 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/text.py:278 ../linkcheck/logger/html.py:280 #, python-format msgid "URL lengths: min=%(min)d, max=%(max)d, avg=%(avg)d." msgstr "" #: ../linkcheck/logger/text.py:283 ../linkcheck/logger/html.py:285 msgid "No statistics available since no URLs were checked." 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:278 #, python-format msgid "Happy birthday for LinkChecker, I'm %d years old today!" msgstr "" #: ../linkcheck/logger/__init__.py:377 #, python-format msgid "created by %(app)s at %(time)s" msgstr "" #: ../linkcheck/logger/html.py:273 msgid "Statistics" msgstr "" #: ../linkcheck/logger/html.py:293 #, python-format msgid "%d link checked." msgid_plural "%d links checked." msgstr[0] "" msgstr[1] "" #: ../linkcheck/logger/html.py:321 #, python-format msgid "Get the newest version at %s" msgstr "" #: ../linkcheck/logger/html.py:324 #, python-format msgid "Write comments and bugs to %s" msgstr "" #: ../linkchecker:55 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" " o When checking 'news:' links the given NNTP host doesn't need to be the\n" " same as the host of the user browsing your pages.\n" msgstr "" #: ../linkchecker:71 msgid "" "PROXY SUPPORT\n" "To use a proxy on Unix or Windows set $http_proxy, $https_proxy or " "$ftp_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, and gconf or KDE on Linux systems.\n" "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 "" #: ../linkchecker:96 msgid "" "REGULAR EXPRESSIONS\n" "Only Python regular expressions are accepted by LinkChecker.\n" "See http://www.amk.ca/python/howto/regex/ 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 "" #: ../linkchecker:105 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 "" #: ../linkchecker:133 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 "" #: ../linkchecker:140 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 "" #: ../linkchecker:164 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" "blacklist\n" " Suitable for cron jobs. Logs the check result into a file\n" " ~/.linkchecker/blacklist which only contains entries with invalid\n" " URLs and the number of times they have failed.\n" "none Logs nothing. Suitable for debugging or checking the exit code.\n" msgstr "" #: ../linkchecker:189 msgid "" "IGNORE WARNINGS\n" "The following warnings are recognized in the 'ignorewarnings' config\n" "file entry:\n" msgstr "" #: ../linkchecker:219 msgid "General options" msgstr "" #: ../linkchecker:223 #, python-format msgid "" "Use FILENAME as configuration file. Per default LinkChecker uses\n" "~/.linkchecker/linkcheckerrc (under Windows\n" "%%HOMEPATH%%\\.linkchecker\\linkcheckerrc)." msgstr "" #: ../linkchecker:228 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 "" #: ../linkchecker:231 msgid "Print version and exit." msgstr "" #: ../linkchecker:234 msgid "Print available check plugins and exit." msgstr "" #: ../linkchecker:237 msgid "Read list of white-space separated URLs to check from stdin." msgstr "" #: ../linkchecker:240 msgid "Output options" msgstr "" #: ../linkchecker:251 #, 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 "" #: ../linkchecker:262 #, python-format msgid "" "Output to a file linkchecker-out.TYPE, $HOME/.linkchecker/blacklist for\n" "'blacklist' 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 http://docs.python.org/lib/standard-encodings." "html.\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 "" #: ../linkchecker:276 msgid "Do not print check status messages." msgstr "" #: ../linkchecker:278 msgid "Don't log warnings. Default is to log warnings." msgstr "" #: ../linkchecker:281 #, 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 http://docs.python.org/lib/standard-encodings." "html." msgstr "" #: ../linkchecker:291 msgid "" "Quiet operation, an alias for '-o none'.\n" "This is only useful with -F." msgstr "" #: ../linkchecker:300 msgid "Log all URLs. Default is to log only errors and warnings." msgstr "" #: ../linkchecker:312 msgid "Checking options" msgstr "" #: ../linkchecker:321 msgid "" "Read a file with initial cookie data. The cookie data format is\n" "explained below." msgstr "" #: ../linkchecker:325 msgid "Disable robots.txt checks" msgstr "" #: ../linkchecker:327 msgid "Check external URLs." msgstr "" #: ../linkchecker:330 msgid "" "Only check syntax of URLs matching the given regular expression.\n" " This option can be given multiple times." msgstr "" #: ../linkchecker:334 msgid "" "Check but do not recurse into URLs matching the given regular\n" "expression. This option can be given multiple times." msgstr "" #: ../linkchecker:338 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 "" #: ../linkchecker:344 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 "" #: ../linkchecker:354 msgid "" "Check recursively all links up to given depth. A negative depth\n" "will enable infinite recursion. Default depth is infinite." msgstr "" #: ../linkchecker:359 #, python-format msgid "" "Set the timeout for connection attempts in seconds. The default\n" "timeout is %d seconds." msgstr "" #: ../linkchecker:363 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 "" #: ../linkchecker:368 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 "" #: ../linkchecker:402 #, python-format msgid "Invalid debug level %(level)r" msgstr "" #: ../linkchecker:415 #, python-format msgid "Unreadable config file: %r" msgstr "" #: ../linkchecker:423 msgid "Running with python -O disables debugging." msgstr "" #: ../linkchecker:453 ../linkchecker:485 #, python-format msgid "Unknown logger type %(type)r in %(output)r for option %(option)s" msgstr "" #: ../linkchecker:457 ../linkchecker:491 #, python-format msgid "Unknown encoding %(encoding)r in %(output)r for option %(option)s" msgstr "" #: ../linkchecker:503 #, python-format msgid "Enter LinkChecker HTTP/FTP password for user %(user)s:" msgstr "" #: ../linkchecker:506 msgid "Enter LinkChecker HTTP/FTP password:" msgstr "" #: ../linkchecker:525 #, python-format msgid "Illegal argument %(arg)r for option %(option)s" msgstr "" #: ../linkchecker:542 #, python-format msgid "Enter LinkChecker password for user %(user)s at %(strpattern)s:" msgstr "" #: ../linkchecker:551 #, python-format msgid "Could not read cookie file %s" msgstr "" #: ../linkchecker:576 msgid "no files or URLs given" msgstr "" #: ../linkchecker:581 #, python-format msgid "" "Overwrite profiling file %(file)r?\n" "Press Ctrl-C to cancel, RETURN to continue." msgstr "" #: ../linkchecker:586 msgid "Canceled." msgstr "" #: ../linkchecker:590 msgid "" "The `yappi' Python module is not installed, therefore the --profile option is " "disabled." msgstr "" #: ../linkchecker:606 msgid "Dumping memory statistics..." msgstr "" #: ../linkchecker:608 #, python-format msgid "The memory dump has been written to `%(filename)s'." msgstr "" #: /usr/lib/python3.8/argparse.py:295 msgid "usage: " msgstr "" #: /usr/lib/python3.8/argparse.py:846 msgid ".__call__() not defined" msgstr "" #: /usr/lib/python3.8/argparse.py:1149 #, python-format msgid "unknown parser %(parser_name)r (choices: %(choices)s)" msgstr "" #: /usr/lib/python3.8/argparse.py:1209 #, python-format msgid "argument \"-\" with mode %r" msgstr "" #: /usr/lib/python3.8/argparse.py:1218 #, python-format msgid "can't open '%(filename)s': %(error)s" msgstr "" #: /usr/lib/python3.8/argparse.py:1427 #, python-format msgid "cannot merge actions - two groups are named %r" msgstr "" #: /usr/lib/python3.8/argparse.py:1465 msgid "'required' is an invalid argument for positionals" msgstr "" #: /usr/lib/python3.8/argparse.py:1487 #, python-format msgid "" "invalid option string %(option)r: must start with a character %(prefix_chars)r" msgstr "" #: /usr/lib/python3.8/argparse.py:1507 #, python-format msgid "dest= is required for options like %r" msgstr "" #: /usr/lib/python3.8/argparse.py:1524 #, python-format msgid "invalid conflict_resolution value: %r" msgstr "" #: /usr/lib/python3.8/argparse.py:1542 #, python-format msgid "conflicting option string: %s" msgid_plural "conflicting option strings: %s" msgstr[0] "" msgstr[1] "" #: /usr/lib/python3.8/argparse.py:1608 msgid "mutually exclusive arguments must be optional" msgstr "" #: /usr/lib/python3.8/argparse.py:1671 msgid "positional arguments" msgstr "" #: /usr/lib/python3.8/argparse.py:1672 msgid "optional arguments" msgstr "" #: /usr/lib/python3.8/argparse.py:1687 msgid "show this help message and exit" msgstr "" #: /usr/lib/python3.8/argparse.py:1718 msgid "cannot have multiple subparser arguments" msgstr "" #: /usr/lib/python3.8/argparse.py:1770 /usr/lib/python3.8/argparse.py:2277 #, python-format msgid "unrecognized arguments: %s" msgstr "" #: /usr/lib/python3.8/argparse.py:1867 #, python-format msgid "not allowed with argument %s" msgstr "" #: /usr/lib/python3.8/argparse.py:1913 /usr/lib/python3.8/argparse.py:1927 #, python-format msgid "ignored explicit argument %r" msgstr "" #: /usr/lib/python3.8/argparse.py:2034 #, python-format msgid "the following arguments are required: %s" msgstr "" #: /usr/lib/python3.8/argparse.py:2049 #, python-format msgid "one of the arguments %s is required" msgstr "" #: /usr/lib/python3.8/argparse.py:2092 msgid "expected one argument" msgstr "" #: /usr/lib/python3.8/argparse.py:2093 msgid "expected at most one argument" msgstr "" #: /usr/lib/python3.8/argparse.py:2094 msgid "expected at least one argument" msgstr "" #: /usr/lib/python3.8/argparse.py:2098 #, python-format msgid "expected %s argument" msgid_plural "expected %s arguments" msgstr[0] "" msgstr[1] "" #: /usr/lib/python3.8/argparse.py:2156 #, python-format msgid "ambiguous option: %(option)s could match %(matches)s" msgstr "" #: /usr/lib/python3.8/argparse.py:2220 #, python-format msgid "unexpected option string: %s" msgstr "" #: /usr/lib/python3.8/argparse.py:2417 #, python-format msgid "%r is not callable" msgstr "" #: /usr/lib/python3.8/argparse.py:2434 #, python-format msgid "invalid %(type)s value: %(value)r" msgstr "" #: /usr/lib/python3.8/argparse.py:2445 #, python-format msgid "invalid choice: %(value)r (choose from %(choices)s)" msgstr "" #: /usr/lib/python3.8/argparse.py:2521 #, python-format msgid "%(prog)s: error: %(message)s\n" msgstr "" linkchecker-10.0.1/pytest.ini000066400000000000000000000000641400504243600161020ustar00rootroot00000000000000[pytest] testpaths = tests addopts = -ra --tb=short linkchecker-10.0.1/requirements.txt000066400000000000000000000001431400504243600173330ustar00rootroot00000000000000# required: beautifulsoup4 >= 4.8.1 requests >= 2.4 pyxdg dnspython >= 2.0 # optional: argcomplete linkchecker-10.0.1/robots.txt000066400000000000000000000006031400504243600161210ustar00rootroot00000000000000# 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.0.1/scripts/000077500000000000000000000000001400504243600155405ustar00rootroot00000000000000linkchecker-10.0.1/scripts/analyze_memdump.py000077500000000000000000000076171400504243600213170ustar00rootroot00000000000000#!/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.0.1/scripts/nodebug.sh000077500000000000000000000002721400504243600175230ustar00rootroot00000000000000#!/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.0.1/scripts/removeafter.py000077500000000000000000000006621400504243600204400ustar00rootroot00000000000000#!/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.0.1/scripts/update_iana_uri_schemes.py000066400000000000000000000055231400504243600227570ustar00rootroot00000000000000import 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", "isbn": "ISBN (int. book numbers)", "javascript": "JavaScript", "slack": "Slack Technologies client", } filter_uri_schemes_permanent = ( "file", "ftp", "http", "https", "mailto", "news", "nntp", ) 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 = "^(%%s%%s%%s%%s)$" %% ( 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 = [ "|%s # %s" % (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 if status not in res: res[status] = {} res[status][scheme] = description if __name__ == "__main__": sys.exit(main(sys.argv[1:])) linkchecker-10.0.1/scripts/update_iana_uri_schemes.sh000077500000000000000000000004441400504243600227410ustar00rootroot00000000000000#!/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.0.1/scripts/viewprof.py000077500000000000000000000004211400504243600177530ustar00rootroot00000000000000#!/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.0.1/setup.cfg000066400000000000000000000035571400504243600157040ustar00rootroot00000000000000[global] ;command_packages = distcmds [bdist_rpm] release = 1 packager = Bastian Kleineidam doc_files = doc/examples/ cgi-bin/lconline/ provides = linkchecker group = Applications/Internet install_script = install-rpm.sh python = python [bdist_wheel] universal = 0 [check-manifest] ignore-bad-ideas = *.mo ignore = *.rej [flake8] filename = *.py ./linkchecker 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 linkchecker: E402 setup.py: E402 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 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.0.1/setup.py000077500000000000000000000327251400504243600155770ustar00rootroot00000000000000#!/usr/bin/python3 # 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. """ Setup file for the distuils module. It includes the following features: - creation and installation of configuration files with installation data - automatic generation of .mo locale files - automatic permission setting on POSIX systems for installed files Because of all the features, this script is nasty and big. Change it very carefully. """ import sys if sys.version_info < (3, 6, 0, "final", 0): raise SystemExit("This program requires Python 3.6 or later.") import os import re import stat import glob # import Distutils stuff from setuptools import find_packages, setup from distutils.command.install_lib import install_lib from distutils.command.clean import clean from distutils.command.install_data import install_data from distutils.dir_util import remove_tree from distutils.file_util import write_file from distutils import util, log from distutils.core import Distribution # the application version AppVersion = "10.0.1" # the application name AppName = "LinkChecker" Description = "check links in web documents or full websites" def get_long_description(): """Try to read long description from README.rst.""" try: with open("README.rst") as f: return f.read() except Exception: return Description def normpath(path): """Norm a path name to platform specific notation.""" return os.path.normpath(path) def cnormpath(path): """Norm a path name to platform specific notation and make it absolute.""" path = normpath(path) if os.name == "nt": # replace slashes with backslashes path = path.replace("/", "\\") if not os.path.isabs(path): path = normpath(os.path.join(sys.prefix, path)) return path release_ro = re.compile(r"\(released (.+)\)") def get_release_date(): """Parse and return relase date as string from doc/changelog.txt.""" fname = os.path.join("doc", "changelog.txt") release_date = "unknown" with open(fname) as fd: # the release date is on the first line line = fd.readline() mo = release_ro.search(line) if mo: release_date = mo.groups(1) return release_date def get_portable(): """Return portable flag as string.""" return os.environ.get("LINKCHECKER_PORTABLE", "0") class MyInstallLib(install_lib): """Custom library installation.""" def install(self): """Install the generated config file.""" outs = super().install() infile = self.create_conf_file() outfile = os.path.join(self.install_dir, os.path.basename(infile)) self.copy_file(infile, outfile) outs.append(outfile) return outs def create_conf_file(self): """Create configuration file.""" cmd_obj = self.distribution.get_command_obj("install") cmd_obj.ensure_finalized() # we have to write a configuration file because we need the # directory (and other stuff like author, url, ...) # all paths are made absolute by cnormpath() data = [] for d in ["purelib", "platlib", "lib", "headers", "scripts", "data"]: attr = "install_%s" % d if cmd_obj.root: # cut off root path prefix cutoff = len(cmd_obj.root) # don't strip the path separator if cmd_obj.root.endswith(os.sep): cutoff -= 1 val = getattr(cmd_obj, attr)[cutoff:] else: val = getattr(cmd_obj, attr) if attr == "install_data": cdir = os.path.join(val, "share", "linkchecker") data.append("config_dir = %r" % cnormpath(cdir)) elif attr == "install_lib": if cmd_obj.root: _drive, tail = os.path.splitdrive(val) if tail.startswith(os.sep): tail = tail[1:] self.install_lib = os.path.join(cmd_obj.root, tail) else: self.install_lib = val data.append("%s = %r" % (attr, cnormpath(val))) self.distribution.create_conf_file(data, directory=self.install_lib) return self.get_conf_output() def get_conf_output(self): """Get name of configuration file.""" return self.distribution.get_conf_filename(self.install_lib) def get_outputs(self): """Add the generated config file to the list of outputs.""" outs = super().get_outputs() conf_output = self.get_conf_output() outs.append(conf_output) if self.compile: outs.extend(self._bytecode_filenames([conf_output])) return outs class MyInstallData(install_data): """Fix file permissions.""" def run(self): """Adjust permissions on POSIX systems.""" self.install_translations() super().run() self.fix_permissions() def install_translations(self): """Install compiled gettext catalogs.""" # A hack to fix https://github.com/linkchecker/linkchecker/issues/102 i18n_files = [] data_files = [] for dir, files in self.data_files: if "LC_MESSAGES" in dir: i18n_files.append((dir, files)) else: data_files.append((dir, files)) self.data_files = data_files # We do almost the same thing that install_data.run() does, except # we can assume everything in self.data_files is a (dir, files) tuple, # and all files lists are non-empty. And for i18n files, instead of # specifying the directory we instead specify the destination filename. for dest, files in i18n_files: dest = util.convert_path(dest) if not os.path.isabs(dest): dest = os.path.join(self.install_dir, dest) elif self.root: dest = util.change_root(self.root, dest) self.mkpath(os.path.dirname(dest)) for data in files: data = util.convert_path(data) (out, _) = self.copy_file(data, dest) self.outfiles.append(out) def fix_permissions(self): """Set correct read permissions on POSIX systems. Might also be possible by setting umask?""" if os.name == "posix" and not self.dry_run: # Make the data files we just installed world-readable, # and the directories world-executable as well. for path in self.get_outputs(): mode = os.stat(path)[stat.ST_MODE] if stat.S_ISDIR(mode): mode |= 0o11 mode |= 0o44 os.chmod(path, mode) class MyDistribution(Distribution): """Custom distribution class generating config file.""" def __init__(self, attrs): """Set console and windows scripts.""" super().__init__(attrs) self.console = ["linkchecker"] def run_commands(self): """Generate config file and run commands.""" cwd = os.getcwd() data = [] data.append("config_dir = %r" % os.path.join(cwd, "config")) data.append("install_data = %r" % cwd) data.append("install_scripts = %r" % cwd) self.create_conf_file(data) super().run_commands() def get_conf_filename(self, directory): """Get name for config file.""" return os.path.join(directory, "_%s_configdata.py" % self.get_name()) def create_conf_file(self, data, directory=None): """Create local config file from given data (list of lines) in the directory (or current directory if not given).""" data.insert(0, "# this file is automatically created by setup.py") data.insert(0, "# -*- coding: iso-8859-1 -*-") if directory is None: directory = os.getcwd() filename = self.get_conf_filename(directory) # add metadata metanames = ( "name", "version", "author", "author_email", "maintainer", "maintainer_email", "url", "license", "description", "long_description", "keywords", "platforms", "fullname", "contact", "contact_email", ) for name in metanames: method = "get_" + name val = getattr(self.metadata, method)() cmd = "%s = %r" % (name, val) data.append(cmd) data.append('release_date = "%s"' % get_release_date()) data.append("portable = %s" % get_portable()) # write the config file util.execute( write_file, (filename, data), "creating %s" % filename, self.verbose >= 1, self.dry_run, ) def list_message_files(package, suffix=".mo"): """Return list of all found message files and their installation paths.""" for fname in glob.glob("po/*" + suffix): # basename (without extension) is a locale name localename = os.path.splitext(os.path.basename(fname))[0] domainname = "%s.mo" % package.lower() yield ( fname, os.path.join("share", "locale", localename, "LC_MESSAGES", domainname), ) class MyClean(clean): """Custom clean command.""" def run(self): """Remove share directory on clean.""" if self.all: # remove share directory directory = os.path.join("build", "share") if os.path.exists(directory): remove_tree(directory, dry_run=self.dry_run) else: log.warn("'%s' does not exist -- can't clean it", directory) clean.run(self) # scripts scripts = ["linkchecker"] myname = "LinkChecker Authors" myemail = "" data_files = [ ("share/linkchecker", ["config/linkcheckerrc"]), ( "share/linkchecker/examples", [ "cgi-bin/lconline/leer.html.en", "cgi-bin/lconline/leer.html.de", "cgi-bin/lconline/index.html", "cgi-bin/lconline/lc_cgi.html.en", "cgi-bin/lconline/lc_cgi.html.de", "cgi-bin/lconline/check.js", "cgi-bin/lc.wsgi", "config/linkchecker.apache2.conf", ], ), ] for (src, dst) in list_message_files(AppName): data_files.append((dst, [src])) if os.name == "posix": data_files.append(("share/man/man1", ["doc/man/en/linkchecker.1"])) data_files.append(("share/man/man5", ["doc/man/en/linkcheckerrc.5"])) data_files.append(("share/man/de/man1", ["doc/man/de/linkchecker.1"])) data_files.append(("share/man/de/man5", ["doc/man/de/linkcheckerrc.5"])) data_files.append( ( "share/linkchecker/examples", [ "config/linkchecker-completion", "doc/examples/check_failures.sh", "doc/examples/check_for_x_errors.sh", "doc/examples/check_urls.sh", ], ) ) setup( name=AppName, version=AppVersion, description=Description, keywords="link,url,site,checking,crawling,verification,validation", author=myname, author_email=myemail, maintainer=myname, maintainer_email=myemail, url="https://linkchecker.github.io/linkchecker/", license="GPL", long_description=get_long_description(), long_description_content_type="text/x-rst", distclass=MyDistribution, cmdclass={ "install_lib": MyInstallLib, "install_data": MyInstallData, "clean": MyClean, }, packages=find_packages(include=["linkcheck", "linkcheck.*"]), scripts=scripts, data_files=data_files, classifiers=[ "Topic :: Internet :: WWW/HTTP :: Site Management :: Link Checking", "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: GNU General Public License (GPL)", "Programming Language :: Python", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", ], options={}, # Requirements, usable with setuptools or the new Python packaging module. python_requires=">= 3.6", install_requires=[ "requests >= 2.4", "dnspython >= 2.0", "beautifulsoup4", "pyxdg", ], # Commented out since they are untested and not officially supported. # See also doc/install.txt for more detailed dependency documentation. # extra_requires = { # "IP country info": ['GeoIP'], # https://pypi.org/project/GeoIP/ # "GNOME proxies": ['PyGObject'], # https://pypi.org/project/PyGObject/ # "Bash completion": ['argcomplete'], # https://pypi.org/project/argcomplete/ # "Memory debugging": ['meliae'], # https://pypi.org/project/meliae/ # } ) linkchecker-10.0.1/tests/000077500000000000000000000000001400504243600152135ustar00rootroot00000000000000linkchecker-10.0.1/tests/__init__.py000066400000000000000000000157661400504243600173430ustar00rootroot00000000000000# 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 pytest from contextlib import contextmanager from functools import lru_cache, wraps from linkcheck import LinkCheckerInterrupt basedir = os.path.dirname(__file__) linkchecker_cmd = os.path.join(os.path.dirname(basedir), "linkchecker") 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): """Decorator skipping test if given testfunc fails.""" def check_func(func): @wraps(func) def newfunc(*args, **kwargs): if not testfunc(): pytest.skip("%s is not available" % name) 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") @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") @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") @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_newsserver(server): import nntplib try: nntp = nntplib.NNTP(server, usenetrc=False) nntp.quit() return True except nntplib.NNTPError: return False def need_newsserver(server): """Decorator skipping test if newsserver is not available.""" def check_func(func): def newfunc(*args, **kwargs): if not has_newsserver(server): pytest.skip("Newsserver `%s' is not available" % server) return func(*args, **kwargs) newfunc.__name__ = func.__name__ return newfunc return check_func @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") @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.0.1/tests/cache/000077500000000000000000000000001400504243600162565ustar00rootroot00000000000000linkchecker-10.0.1/tests/cache/__init__.py000066400000000000000000000000001400504243600203550ustar00rootroot00000000000000linkchecker-10.0.1/tests/cache/test_urlqueue.py000066400000000000000000000132541400504243600215430ustar00rootroot00000000000000# 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 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): self.result_cache = ResultCache() 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.0.1/tests/checker/000077500000000000000000000000001400504243600166175ustar00rootroot00000000000000linkchecker-10.0.1/tests/checker/__init__.py000066400000000000000000000253361400504243600207410ustar00rootroot00000000000000# 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 funtional for LinkChecker tests. """ import os import re import difflib import unittest import linkcheck.checker import linkcheck.configuration import linkcheck.director import linkcheck.logger from .. import get_file # 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 and "Using proxy" 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) # uncomment for debugging # config.init_logging(None, debug=["all"]) 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(unittest.TestCase): """ Functional test class with ability to test local files. """ logger = TestLogger def setUp(self): """Ensure the current locale setting is the default. Otherwise, warnings will get translated and will break tests.""" super().setUp() linkcheck.init_i18n(loc="C") 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, "r", 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) diff = aggregate.config["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)) 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.0.1/tests/checker/cgi-bin/000077500000000000000000000000001400504243600201275ustar00rootroot00000000000000linkchecker-10.0.1/tests/checker/cgi-bin/input2cookies.py000077500000000000000000000002571400504243600233060ustar00rootroot00000000000000#!/usr/bin/python3 import cgi from http import cookies form = cgi.FieldStorage() C = cookies.SimpleCookie() for field in form: C[field] = form.getvalue(field) print(C) linkchecker-10.0.1/tests/checker/data/000077500000000000000000000000001400504243600175305ustar00rootroot00000000000000linkchecker-10.0.1/tests/checker/data/Bookmarks000066400000000000000000000012511400504243600214020ustar00rootroot00000000000000{ "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.0.1/tests/checker/data/Bookmarks.result000066400000000000000000000004301400504243600227150ustar00rootroot00000000000000url 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.0.1/tests/checker/data/a b/000077500000000000000000000000001400504243600201525ustar00rootroot00000000000000linkchecker-10.0.1/tests/checker/data/a b/el.html000066400000000000000000000000421400504243600214340ustar00rootroot00000000000000External link linkchecker-10.0.1/tests/checker/data/a b/t.txt000066400000000000000000000000021400504243600211460ustar00rootroot00000000000000 linkchecker-10.0.1/tests/checker/data/all_parts_linenos.html000066400000000000000000000002701400504243600241250ustar00rootroot00000000000000 linkchecker-10.0.1/tests/checker/data/all_parts_linenos.html.result000066400000000000000000000014041400504243600254420ustar00rootroot00000000000000url 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.0.1/tests/checker/data/anchor.html000066400000000000000000000000331400504243600216640ustar00rootroot00000000000000
linkchecker-10.0.1/tests/checker/data/archive.html000066400000000000000000000001321400504243600220330ustar00rootroot00000000000000 linkchecker-10.0.1/tests/checker/data/archive.html.result000066400000000000000000000006271400504243600233610ustar00rootroot00000000000000url 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.0.1/tests/checker/data/base/000077500000000000000000000000001400504243600204425ustar00rootroot00000000000000linkchecker-10.0.1/tests/checker/data/base/test.txt000066400000000000000000000000001400504243600221500ustar00rootroot00000000000000linkchecker-10.0.1/tests/checker/data/base1.html000066400000000000000000000002701400504243600214100ustar00rootroot00000000000000 linkchecker-10.0.1/tests/checker/data/base1.html.result000066400000000000000000000006471400504243600227350ustar00rootroot00000000000000url 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.0.1/tests/checker/data/base2.html000066400000000000000000000001001400504243600214010ustar00rootroot00000000000000 linkchecker-10.0.1/tests/checker/data/base2.html.result000066400000000000000000000005751400504243600227360ustar00rootroot00000000000000url 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.0.1/tests/checker/data/base3.html000066400000000000000000000001041400504243600214060ustar00rootroot00000000000000 linkchecker-10.0.1/tests/checker/data/base3.html.result000066400000000000000000000005751400504243600227370ustar00rootroot00000000000000url 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.0.1/tests/checker/data/base4.html000066400000000000000000000004261400504243600214160ustar00rootroot00000000000000 Blubb linkchecker-10.0.1/tests/checker/data/base4.html.result000066400000000000000000000006101400504243600227260ustar00rootroot00000000000000url 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.0.1/tests/checker/data/charsets/000077500000000000000000000000001400504243600213445ustar00rootroot00000000000000linkchecker-10.0.1/tests/checker/data/charsets/cp1250.html000066400000000000000000000003021400504243600231370ustar00rootroot00000000000000 luouk k pl belsk dy luouk k pl belsk dy linkchecker-10.0.1/tests/checker/data/charsets/cp1250.html.result000066400000000000000000000011361400504243600244620ustar00rootroot00000000000000url 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.0.1/tests/checker/data/charsets/iso8859-2.html000066400000000000000000000003061400504243600235200ustar00rootroot00000000000000 luouk k pl belsk dy luouk k pl belsk dy linkchecker-10.0.1/tests/checker/data/charsets/iso8859-2.html.result000066400000000000000000000011521400504243600250350ustar00rootroot00000000000000url 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.0.1/tests/checker/data/charsets/utf8.html000066400000000000000000000002641400504243600231220ustar00rootroot00000000000000 Žluťoučký kúň úpěl ďábelské ódy ůůůů Žluťoučký kúň úpěl ďábelské ódy ůůůů linkchecker-10.0.1/tests/checker/data/charsets/utf8.html.result000066400000000000000000000011261400504243600244350ustar00rootroot00000000000000url 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.0.1/tests/checker/data/cookies.txt000066400000000000000000000002371400504243600217270ustar00rootroot00000000000000Host: 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.0.1/tests/checker/data/dir.result000066400000000000000000000006421400504243600215500ustar00rootroot00000000000000url 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.0.1/tests/checker/data/dir.zip000066400000000000000000000004261400504243600210340ustar00rootroot00000000000000PK t9dir/UT %I%IUxPK t93 dir/.datUT %I%IUx PK t9 Adir/UT%IUxPK t93 7dir/.datUT%IUxPKylinkchecker-10.0.1/tests/checker/data/empty.html000066400000000000000000000000001400504243600215420ustar00rootroot00000000000000linkchecker-10.0.1/tests/checker/data/empty.html.result000066400000000000000000000002641400504243600230730ustar00rootroot00000000000000url 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.0.1/tests/checker/data/favicon.ico000066400000000000000000000003061400504243600216500ustar00rootroot00000000000000( linkchecker-10.0.1/tests/checker/data/file.asc000066400000000000000000000000221400504243600211310ustar00rootroot00000000000000file:///etc/group linkchecker-10.0.1/tests/checker/data/file.asc.result000066400000000000000000000002541400504243600224550ustar00rootroot00000000000000url 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 valid linkchecker-10.0.1/tests/checker/data/file.css000066400000000000000000000001511400504243600211560ustar00rootroot00000000000000@font-face { src:url(file.html) } background-image:url(file.txt) /*background-image:url(broken.html)*/ linkchecker-10.0.1/tests/checker/data/file.css.result000066400000000000000000000006311400504243600224760ustar00rootroot00000000000000url 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.0.1/tests/checker/data/file.doc000066400000000000000000000220001400504243600211300ustar00rootroot00000000000000ࡱ;  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.0.1/tests/checker/data/file.doc.result000066400000000000000000000005351400504243600224560ustar00rootroot00000000000000url 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.0.1/tests/checker/data/file.html000066400000000000000000000001631400504243600213350ustar00rootroot00000000000000relative url javascript url anchor linkchecker-10.0.1/tests/checker/data/file.html.result000066400000000000000000000005011400504243600226460ustar00rootroot00000000000000url 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.0.1/tests/checker/data/file.markdown000066400000000000000000000004431400504243600222140ustar00rootroot00000000000000# 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.0.1/tests/checker/data/file.markdown.result000066400000000000000000000016651400504243600235400ustar00rootroot00000000000000url 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 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.0.1/tests/checker/data/file.pdf000066400000000000000000000163631400504243600211530ustar00rootroot00000000000000%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.0.1/tests/checker/data/file.pdf.result000066400000000000000000000006261400504243600224630ustar00rootroot00000000000000url 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.0.1/tests/checker/data/file.php000066400000000000000000000002601400504243600211560ustar00rootroot00000000000000Bla PHP 1 PHP 2 linkchecker-10.0.1/tests/checker/data/file.php.result000066400000000000000000000014141400504243600224750ustar00rootroot00000000000000url 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.0.1/tests/checker/data/file.txt000066400000000000000000000000221400504243600212020ustar00rootroot00000000000000file:///etc/group linkchecker-10.0.1/tests/checker/data/file.txt.result000066400000000000000000000002541400504243600225260ustar00rootroot00000000000000url 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 valid linkchecker-10.0.1/tests/checker/data/file.wml000066400000000000000000000003771400504243600211770ustar00rootroot00000000000000

Test1

linkchecker-10.0.1/tests/checker/data/file.wml.result000066400000000000000000000006471400504243600225140ustar00rootroot00000000000000url 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.0.1/tests/checker/data/file_url_quote.html000066400000000000000000000005651400504243600234420ustar00rootroot00000000000000 l1 The same address as l1 therefore not reported l2 l3 l4 linkchecker-10.0.1/tests/checker/data/file_url_quote.html.result000066400000000000000000000014661400504243600247600ustar00rootroot00000000000000url 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.0.1/tests/checker/data/frames.html000066400000000000000000000003031400504243600216670ustar00rootroot00000000000000 linkchecker-10.0.1/tests/checker/data/frames.html.result000066400000000000000000000006451400504243600232150ustar00rootroot00000000000000url 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.0.1/tests/checker/data/html5.html000066400000000000000000000002571400504243600214530ustar00rootroot00000000000000