Example #1
0
def cmd(message, **kwargs):
    """The *text* command creates an NFC Forum Text Record with the given
    input text. The text language defaults to 'en' and can be set
    with --language followed by the IANA language code.

    \b
    Examples:
      ndeftool text '' | hexdump -Cv
      ndeftool text 'Created with the nfcpy ndeftool.' print
      ndeftool text 'first record' text 'second record' print
      ndeftool text -l en 'English' text -l de 'Deutsch' print

    """
    dmsg(__name__ + ' ' + str(kwargs))

    if message is None:
        message = []

    content = kwargs['text']
    language = kwargs['language']
    encoding = kwargs['encoding']

    record = ndef.TextRecord(content, language, encoding)

    message.append(record)
    return message
Example #2
0
def load_file(f, decode_errors):
    fn = getattr(f, 'name', '<stdin>')
    try:
        records = list(ndef.message_decoder(f.read(), decode_errors))
        info("loaded %d record(s) from %s" % (len(records), fn))
        return records
    except ndef.DecodeError as error:
        dmsg(str(error))
        errmsg = "%s does not contain a valid NDEF message." % fn
        raise click.ClickException(errmsg)
Example #3
0
def cmd(message, **kwargs):
    """The *smartposter* command creates an NFC Forum Smart Poster Record
    for the resource identifier. A smart poster record combines the
    uniform resource identifier with additional data such as titles
    and icons for representation and processing instructions for the
    reader application.

    A smart poster should have title text entries for the desired
    languages, added with repetitive '-t' options. An English title
    text may also be added with '-T'. The recommended action set with
    '-a' tells the reader application to either run the default action
    for the URI, save it for later or open for editing.

    A smart poster may also provide a collection of icons for
    graphical representation. An icon file is added with the '-i'
    option which may be used more than once. The icon type is
    determined from the file content and must be an 'image' or 'video'
    mime type.

    \b
    Examples:
      ndeftool smartposter http://nfcpy.org print
      ndeftool smartposter -T 'nfcpy project' http://nfcpy.org print
      ndeftool smartposter -t en 'nfcpy project' http://nfcpy.org print
      ndeftool smartposter -T 'EMERGENCY CALL 911' -a exec tel:911
      ndeftool smartposter -i nfcpy-logo-32x32.ico http://nfcpy.org

    """
    dmsg(__name__ + ' ' + str(kwargs))

    if message is None:
        message = []

    record = ndef.SmartposterRecord(kwargs['resource'])
    for lang, text in kwargs['titles']:
        record.set_title(text, lang)
    if kwargs['title']:
        record.set_title(kwargs['title'], 'en')
    if kwargs['action']:
        record.action = kwargs['action']
    for icon_file in kwargs['icons']:
        icon_data = icon_file.read()
        icon_type = magic.from_buffer(icon_data, mime=True)
        if icon_type.startswith('image/') or icon_type.startswith('video/'):
            record.add_icon(icon_type, icon_data)
        else:
            errmsg = "file %s is not a proper icon file" % icon_file.name
            raise click.ClickException(errmsg)

    message.append(record)
    return message
Example #4
0
def cmd(ctx, message, **kwargs):
    """The *load* command reads records or payloads from disk files or
    standard input. The files to read are searched with the pattern
    specified by PATH which in the simplest form is an existing file
    name. Other forms may include '*', '?' and character ranges
    expressed by '[]'. A single '-' may be used to read from standard
    input. Note that patterns containg wildcards may need to be
    escaped to avoid shell expansion.

    The default mode of operation is to load files containing NDEF
    records. In '--pack' mode the files are loaded into the payload of
    NDEF records with record type (NDEF Record TNF and TYPE) set to
    the mimetype discovered from the payload and record name (NDEF
    Record ID) set to the filename.

    \b
    Examples:
      ndeftool load message.ndef print
      ndeftool load '*.ndef' print
      cat message.ndef | ndeftool load - print
      ndeftool load --pack /etc/hostname print
      ndeftool load --pack '/etc/cron.daily/*' print

    """
    dmsg(__name__ + ' ' + str(kwargs))

    if message is None:
        message = []

    if kwargs['path'] == '-':
        filenames = kwargs['path']
    else:
        filenames = sorted(glob.iglob(kwargs['path']))

    if len(filenames) == 0:
        info("No files selected by path '%s'." % kwargs['path'])

    for filename in filenames:
        try:
            f = click.open_file(filename, 'rb')
        except (OSError, IOError) as error:
            warn(str(error))
        else:
            if kwargs['pack']:
                message.append(pack_file(f))
            else:
                message.extend(load_file(f, ctx.meta['decode-errors']))

    return message
Example #5
0
def cmd(message, **kwargs):
    """The *uri* command creates an NFC Forum URI Record wit the given
    resource identifier. Note that this is actually an
    Internationalized Resource Identifier (IRI).

    \b
    Examples:
      ndeftool uri 'http://nfcpy.org' print

    """
    dmsg(__name__ + ' ' + str(kwargs))

    if message is None:
        message = []

    record = ndef.UriRecord(kwargs['resource'])

    message.append(record)
    return message
Example #6
0
def cmd(ctx, message, **kwargs):
    """The *payload* command either changes the current last record's
    data (NDEF Record PAYLOAD) or, if the current message does
    not have any records, creates a record with the given record
    data. The changed record is verified to successfully encode and
    decode unless disabled with -x.

    The data string may contain hexadecimal bytes using '\\xNN'
    notation where each N is a nibble from [0-F].

    \b
    Examples:
      ndeftool payload 'Hello World' typename 'text/plain' print
      ndeftool payload '\\x02enHello World' typename 'urn:nfc:wkt:T' print -l

    """
    dmsg(__name__ + ' ' + str(kwargs))
    dmsg(repr(kwargs['data']))

    if not message:
        message = [ndef.Record('unknown')]

    record_type = message[-1].type
    record_name = message[-1].name
    record_data = eval(repr(kwargs['data'].encode()).replace('\\\\', '\\'))

    record = ndef.Record(record_type, record_name, record_data)

    if not kwargs['no_check']:
        octets = b''.join(ndef.message_encoder([record]))
        errors = ctx.meta['decode-errors']
        try:
            record = next(ndef.message_decoder(octets, errors))
        except ndef.DecodeError as error:
            raise click.ClickException(str(error))

    message[-1] = record
    return message
Example #7
0
def cmd(message, **kwargs):
    """The *identifier* command either changes the current last record's
    name (NDEF Record ID) or, if the current message does not have any
    records, creates a record with unknown record type and the given
    record name.

    \b
    Examples:
      ndeftool identifier 'record identifier' print
      ndeftool text 'first' id 'r1' text 'second' id 'r2' print

    """
    dmsg(__name__ + ' ' + str(kwargs))

    if not message:
        message = [ndef.Record('unknown')]

    try:
        message[-1].name = kwargs['name'].encode('latin', 'replace')
    except ValueError as error:
        raise click.ClickException(str(error))

    return message
Example #8
0
def cmd(ctx, message, **kwargs):
    """The *typename* command either changes the current last record's
    type (NDEF Record TNF and TYPE) or, if the current message does
    not have any records, creates a record with the given record
    type. The changed record is verified to successfully encode and
    decode unless disabled with -x.

    \b
    Examples:
      ndeftool typename 'text/plain' print
      ndeftool typename 'text/plain' payload 'Hello World' print

    """
    dmsg(__name__ + ' ' + str(kwargs))

    if not message:
        message = [ndef.Record()]

    record_type = kwargs['type'].encode('latin', 'replace')
    record_name = message[-1].name
    record_data = message[-1].data

    try:
        record = ndef.Record(record_type, record_name, record_data)
    except ValueError as error:
        raise click.ClickException(str(error))

    if not kwargs['no_check']:
        octets = b''.join(ndef.message_encoder([record]))
        errors = ctx.meta['decode-errors']
        try:
            record = next(ndef.message_decoder(octets, errors))
        except ndef.DecodeError as error:
            raise click.ClickException(str(error))

    message[-1] = record
    return message
Example #9
0
def cmd(ctx, message, **kwargs):
    """The *print* command outputs a formatted representation of all
    current NDEF Records. By default this is the one line str()
    representation for each record. The '--long' format produces
    multiple indented lines per record in an attempt to provide a more
    readable output. Printing consumes all records so that no more
    data is send to stdout or given to the next command. This can be
    changed with the '--keep' flag.

    When given as the first command *print* attempts to decode an NDEF
    message from standard input and then process the generated list of
    records.

    \b
    Examples:
      ndeftool text 'made with ndeftool' print
      ndeftool text 'say one' print text 'say two' print
      ndeftool text one print --keep text two print
      ndeftool text 'print from stdin' | ndeftool print
      ndeftool text 'before' | ndeftool print text 'after' print

    """
    dmsg(__name__ + ' ' + str(kwargs))

    if message is None:
        info("Reading data from standard input")
        octets = click.get_binary_stream('stdin').read()
        errors = ctx.meta['decode-errors']
        try:
            message = list(ndef.message_decoder(octets, errors))
        except ndef.DecodeError as error:
            raise click.ClickException(str(error))

    for index, record in enumerate(message):
        if not kwargs['long']:
            echo(str(record))
            continue

        if isinstance(record, ndef.TextRecord):
            echo("NFC Forum Text Record [record #{}]".format(index + 1))
            echo(LONG_FORMAT.format("content", record.text))
            echo(LONG_FORMAT.format("language", record.language))
            echo(LONG_FORMAT.format("encoding", record.encoding))
        elif isinstance(record, ndef.UriRecord):
            echo("NFC Forum URI Record [record #{}]".format(index + 1))
            echo(LONG_FORMAT.format("resource", record.iri))
        elif isinstance(record, ndef.SmartposterRecord):
            echo("NFC Forum Smart Poster Record [record #{}]".format(index +
                                                                     1))
            echo(LONG_FORMAT.format("resource", record.resource.iri))
            if record.action:
                echo(LONG_FORMAT.format("action", record.action))
            for lang, text in record.titles.items():
                echo(LONG_FORMAT.format("title_" + lang, text))
            for icon_type, icon_data in record.icons.items():
                echo(LONG_FORMAT.format(icon_type, "%d byte" % len(icon_data)))
        else:
            echo("Record [record #{}]".format(index + 1))
            echo(LONG_FORMAT.format("type", record.type))
            echo(LONG_FORMAT.format("name", record.name))
            echo(LONG_FORMAT.format("data", bytes(record.data)))

    return message if kwargs['keep'] else []
Example #10
0
def cmd(ctx, message, **kwargs):
    """The *save* command writes the current records to disk. The records
    to write can be restricted to the subset selected with '--skip',
    '--count', '--head' and '--tail' applied in that order. The
    default mode is to save all selected records as one NDEF message
    into a single file given by PATH. In '--burst' mode each record is
    written as one NDEF message into a separate file under the
    directory given by PATH. The file names are three digit numbers
    created from the record index. In '--unpack' mode the payload of
    each record is written to a separate file under directory PATH
    with the file name set to the record name (NDEF Record ID).
    Records without name are not written unless '--unpack' and
    '--burst' are both set.

    The *save* command does not replace existing files or directories
    unless this is requested with '--force'.

    The *save* command consumes records from the internal message
    pipe. This can be prevented with '--keep', all records are then
    forwarded to the next command or written to standard output. When
    *save* is the first command it creates the pipe by reading from
    standard input.

    \b
    Examples:
      ndeftool text 'Hello World' save text.ndef
      ndeftool text 'Hello World' | ndeftool save text.ndef
      ndeftool text 'One' save one.ndef text 'Two' save two.ndef

    """
    dmsg(__name__ + ' ' + str(kwargs))

    path = kwargs['path']

    if os.path.exists(path) and not kwargs['force']:
        errmsg = "path '%s' exists. Use '--force' to replace."
        raise click.ClickException(errmsg % path)

    if message is None:
        info("Reading data from standard input")
        octets = click.get_binary_stream('stdin').read()
        errors = ctx.meta['decode-errors']
        try:
            message = list(ndef.message_decoder(octets, errors))
        except ndef.DecodeError as error:
            raise click.ClickException(str(error))

    first = min(kwargs['skip'], len(message))
    count = min(kwargs['count'] or len(message), len(message))
    head = min(kwargs['head'] or count, count)
    tail = min(kwargs['tail'] or count, count)
    dmsg("first=%d count=%d head=%d tail=%d" % (first, count, head, tail))
    count = min(head, tail, len(message) - first)
    first = first + head - min(head, tail)
    dmsg("first=%d count=%d head=%d tail=%d" % (first, count, head, tail))

    if kwargs['burst'] or kwargs['unpack']:
        path = os.path.normpath(path)
        try:
            if os.path.isdir(path):
                shutil.rmtree(path)
            os.mkdir(path)
        except (OSError, IOError) as error:
            raise click.ClickException(str(error))

        for index, record in enumerate(message[first:first + count]):
            name = None
            if kwargs['unpack'] and record.name:
                name = record.name
            if kwargs['burst'] and not name:
                name = '%03d.ndef' % index
            if name:
                with click.open_file('%s/%s' % (path, name), 'wb') as f:
                    info("Saving 1 record to {}.".format(f.name))
                    if kwargs['unpack']:
                        f.write(record.data)
                    else:
                        f.write(b''.join(ndef.message_encoder([record])))
            else:
                warn("Skipping 1 record without name")
    else:
        with click.open_file(path, 'wb') as f:
            filename = f.name if f.name != '-' else '<stdout>'

            info("Saving {num} record{s} to {path}.".format(
                num=count, path=filename, s=('', 's')[count > 1]))

            f.write(b''.join(ndef.message_encoder(message[first:first +
                                                          count])))

    if not kwargs['keep']:
        del message[first:first + count]

    return message