@@ -0,0 +1,1616 @@
+#!/usr/bin/env python3%0A%0Atry:%0A    from PyPDF2 import PdfFileReader%0Aexcept ImportError:%0A    print(%22Please install the PyPDF2 library using %60pip3 install PyPDF2%60.%5Cn%22)%0A    raise%0A%0Afrom collections import deque%0Aimport sys%0A%0Adef get_links_and_destinations(f):%0A    # Based on %3Chttps://stackoverflow.com/a/5978161/393146%3E%0A    pdf = PdfFileReader(f)%0A%0A    links = deque()%0A    dests = deque()%0A    errors = deque()%0A%0A    for pg in range(pdf.getNumPages()):%0A        obj = pdf.getPage(pg).getObject()%0A%0A        for annotation in obj.get('/Annots', %5B%5D):%0A            uri = annotation.getObject().get('/A', %7B%7D).get('/URI', None)%0A            if uri is not None and uri not in links:%0A                links.append(uri)%0A%0A    dests = pdf.getNamedDestinations()%0A%0A    for l in links:%0A        if not l.startswith(%22https:%22):%0A            errors.append(%22Insecure or unrecognized protocol in link: %22 + l)%0A%0A        if l.startswith(%22https://zips.z.cash/protocol/%22):%0A            fragment = l.partition(%22#%22)%5B2%5D%0A            if fragment and fragment not in dests:%0A                errors.append(%22Missing link target: %22 + l)%0A%0A    return (links, dests, errors)%0A%0A%0Adef main(args):%0A    if len(args) %3C 2:%0A        print(%22Usage: ./links_and_dests.py %3Cfile.pdf%3E%22)%0A        return 1%0A%0A    with open(args%5B1%5D, 'rb') as f:%0A        (links, dests, errors) = get_links_and_destinations(f)%0A%0A    print(%22Links:%22)%0A    for l in links:%0A        print(l)%0A%0A    print(%22%5CnDestinations:%22)%0A    for d in dests:%0A        print(d)%0A%0A    if errors:%0A        print(%22%5CnErrors:%22)%0A        for e in errors:%0A            print(e)%0A%0A    return 0%0A%0Aif __name__ == '__main__':%0A    sys.exit(main(sys.argv))%0A

Add links_and_dests.py. This can be used to print outgoing links and targets in the PDF, and detect a subset of errors. It depends on the PyPDF2 library (pip3 install PyPDF2).