node.js bindings for deltachat-core
jikstra 583e0f3e68 Prepare for v1.0.0-alpha.11 1 month ago
.circleci set up circleci 7 months ago
ci_scripts Rust core (#308) 6 months ago
deltachat-core-rust @ 67e2e4d415 Update deltachat-core-rust to 67e2e4d415824f7698488abf609ae9f91c7c92b9 1 month ago
images Document tests and coverage 1 year ago
lib Enable update of DC configurations 1 month ago
scripts Remove unhelpful cargo update in rebuild-core script 4 months ago
src Replace setStringTable with setStockTranslation (#389) 1 month ago
test Enable update of DC configurations 1 month ago
.gitignore Add Prebuildify (#191) 1 year ago
.gitmodules Remove deltachat-core submodule 6 months ago
.npmignore chore: bring back prebuilt binaries (#340) 6 months ago
.npmrc Prevent building package-lock.json 7 months ago
.travis.yml chore: bring back prebuilt binaries (#340) 6 months ago Prepare for v1.0.0-alpha.11 1 month ago Prepare for v1.0.0-alpha.11 1 month ago
LICENSE License (#375) 2 months ago Make it possible to configure {imap,smtp}_certificate_checks (#388) 1 month ago Update changelog 11 months ago
appveyor.yml Remove caching logic on appveyor for windows builds, tries to fix creating prebuilts for windows 4 months ago
binding.gyp Replace setStringTable with setStockTranslation (#389) 1 month ago
binding.js chore: bring back prebuilt binaries (#340) 6 months ago
constants.js Update deltachat-core-rust to 67e2e4d415824f7698488abf609ae9f91c7c92b9 1 month ago
events.js Update deltachat-core-rust to 67e2e4d415824f7698488abf609ae9f91c7c92b9 1 month ago
index.js Fix standard 7 months ago
package.json Prepare for v1.0.0-alpha.11 1 month ago Update readme (#336) 6 months ago


node.js bindings for deltachat-core-rust

Appveyor build status Build Status npm Node version Coverage Status dependencies JavaScript Style Guide

WORK IN PROGRESS The API can change at any time and will not follow semver versioning until v1.0.0 has been released.

If you are upgrading: please see

deltachat-node primarily aims to offer two things:

  • A high level JavaScript api with syntactic sugar
  • A low level c binding api around deltachat-core-rust

Table of Contents

Click to expand


By default the installation will build deltachat-core-rust from the submodule using scripts/rebuild-core.js. Simply invoke npm:

npm install deltchat-node

Using system libdeltachat

It is possible to use the system-wide installed library which will be located using pkg-config. You need to have installed deltachat-core-rust before installing this way. Using this approach allows you to build with your own specific options.

Invoke npm with the extra arguments:

npm install deltachat-node --dc-system-lib=true

When invoking node-gyp directly this can be achieved in a slightly different way:

node-gyp rebuild -- -Dsystem_dc_core=true


const DeltaChat = require('deltachat-node')
const dc = new DeltaChat()

const opts = {
  addr: '[email]',
  mail_pw: '[password]'

const contact = '[email]'

dc.on('ALL', console.log.bind(null, 'core |'))

dc.on('DC_EVENT_INCOMING_MSG', (chatId, msgId) => {
  const msg = dc.getMessage(msgId)
  console.log(chatId, msg)
  dc.sendMessage(chatId, `Bot agrees to ${Math.random() * 100}%`)
}) => {
  const onReady = () => {
    const contactId = dc.createContact('Test', contact)
    const chatId = dc.createChatByContactId(contactId)
    dc.sendMessage(chatId, 'Hi!')
    dc.close(() => {
  if (!dc.isConfigured()) {
    dc.once('ready', onReady)
  } else {


The high level JavaScript API is a collection of classes wrapping most context types provided by deltachat-core-rust. Please see the class list for an overview of this.

dc = DeltaChat()

Creates a new DeltaChat instance.

Initializes the main context and sets up event handling. Call, cb) to start and dc.configure(opts, cb) if needed.

class DeltaChat

The DeltaChat class wraps a dc_context_t* and handles most operations, such as connecting to an IMAP server, sending messages with SMTP etc. It is through this instance you get references to the other class types following below.


Add a number of contacts. Corresponds to dc_add_address_book().

dc.addContactToChat(chatId, contactId)

Add a member to a group. Corresponds to dc_add_contact_to_chat().

dc.archiveChat(chatId, archive)

Archive or unarchive a chat. Corresponds to dc_archive_chat().

dc.blockContact(contactId, block)

Block or unblock a contact. Corresponds to dc_block_contact().


Check a scanned QR code. Corresponds to dc_check_qr().


Stops the threads and closes down the DeltaChat instance. Calls back when underlying context has been fully closed.

dc.configure(options[, cb])

Configure and connect a context. Corresponds to dc_configure().

The options object takes the following properties:

  • options.addr (string, required): Email address of the chat user.
  • options.mail_server (string, optional): IMAP-server, guessed if left out.
  • options.mail_user (string, optional): IMAP-username, guessed if left out.
  • options.mail_pw (string, required): IMAP-password of the chat user.
  • options.mail_port (string | integer, optional): IMAP-port, guessed if left out.
  • options.imap_certificate_checks (string | integer, optional): IMAP certificate checks configuration.
  • options.send_server (string, optional): SMTP-server, guessed if left out.
  • options.send_user (string, optional): SMTP-user, guessed if left out.
  • options.send_pw (string, optional): SMTP-password, guessed if left out.
  • options.send_port (string | integer, optional): SMTP-port, guessed if left out.
  • options.smtp_certificate_checks (string | integer, optional): SMTP certificate checks configuration.
  • options.server_flags (integer, optional): IMAP-/SMTP-flags as a combination of DC_LP flags, guessed if left out.
  • options.displayname (string, optional): Own name to use when sending messages. MUAs are allowed to spread this way e.g. using CC, defaults to empty.
  • options.selfstatus (string, optional): Own status to display e.g. in email footers, defaults to a standard text.
  • options.selfavatar (string, optional): File containing avatar.
  • options.e2ee_enabled (boolean, optional): Enable E2EE. Defaults to true.
  • options.mdns_enabled (boolean, optional): Send and request read receipts. Defaults to true.
  • options.inbox_watch (boolean, optional): Watch INBOX-folder for changes. Defaults to true.
  • options.sentbox_watch (boolean, optional): Watch Sent-folder for changes. Defaults to true.
  • options.mvbox_watch (boolean, optional): Watch DeltaChat-folder for changes. Defaults to true.
  • options.mvbox_move (boolean, optional): Heuristically detect chat-messages and move them to the DeltaChat-folder. Defaults to true.
  • options.show_emails (integer, optional): DC_SHOW_EMAILS_OFF (0) show direct replies to chats only (default), DC_SHOW_EMAILS_ACCEPTED_CONTACTS (1) also show all mails of confirmed contacts, DC_SHOW_EMAILS_ALL (2) also show mails of unconfirmed contacts in the deaddrop.
  • options.save_mime_headers (boolean, optional): Set to true if you want to use dc.getMimeHeaders() later.

dc.continueKeyTransfer(messageId, setupCode, callback)

Continue the AutoCrypt key transfer on another device. Corresponds to dc_continue_key_transfer().

  • messageId (string|integer, required) See deltachat api documentation
  • setupCode (string, required) See deltachat api documentation
  • callback (function, required) Called with an error if setup code is bad


Create a normal chat with a single user. Corresponds to dc_create_chat_by_contact_id().


Create a normal chat or group chat by a message id. Corresponds to dc_create_chat_by_msg_id().

dc.createContact(name, addr)

Add a single contact as a result of an explicit user action. Corresponds to dc_create_contact().


Create a new unverified group chat. Corresponds to dc_create_group_chat().


Create a new verified group chat. Corresponds to dc_create_group_chat().


Delete a chat. Corresponds to dc_delete_chat().


Delete a contact. Corresponds to dc_delete_contact().


Delete messages. Corresponds to dc_delete_msgs().

dc.forwardMessages(messageIds, chatId)

Forward messages to another chat. Corresponds to dc_forward_msgs().


Get the blob directory. Corresponds to dc_get_blobdir().


Get the number of blocked contacts. Corresponds to dc_get_blocked_cnt().


Get blocked contacts. Corresponds to dc_get_blocked_contacts().


Get Chat object by a chat id. Corresponds to `dc_get_chat().


Get contact ids belonging to a chat. Corresponds to dc_get_chat_contacts().


Check, if there is a normal chat with a given contact. Corresponds to `dc_get_chat_id_by_contact_id().

dc.getChatMedia(chatId, msgType1, msgType2, msgType3)

Returns all message ids of the given type in a chat. Corresponds to dc_get_chat_media().

dc.getLocations(chatId, contactId, timestampFrom, timestampTo)

Returns an array of locations for a given chat, contact and timestamp range. Each item in the array is an object with the following properties:

  • accuracy
  • latitude
  • longitude
  • timestamp
  • contactId
  • msgId
  • chatId


Get the raw mime-headers of the given message. Corresponds to dc_get_mime_headers().

dc.getChatMessages(chatId, flags, marker1before)

Get all message ids belonging to a chat. Corresponds to dc_get_chat_msgs().

dc.getChats(listFlags, queryStr, queryContactId)

Like dc.getChatList() but returns a JavaScript array of ids.

dc.getChatList(listFlags, queryStr, queryContactId)

Get a list of chats. Returns a ChatList object. Corresponds to dc_get_chatlist().

DeltaChat.getConfig(path, callback)

Get configuration from a path. Calls back with (err, config). A static method which does a minimal open and if the path has a configured state the config parameter contains the following properties:

  • addr (string): Email address used to configure the account.


Get a configuration option. Corresponds to dc_get_config().


Get a single Contact object. Corresponds to dc_get_contact().


Get encryption info for a contact. Corresponds to dc_get_contact_encrinfo().

dc.getContacts(listFlags, query)

Return known and unblocked contacts. Corresponds to dc_get_contacts().


Get draft for a chat, if any. Corresponds to dc_get_draft().


Get the number of fresh messages in a chat. Corresponds to dc_get_fresh_msg_cnt().


Returns the message ids of all fresh messages of any chat. Corresponds to dc_get_fresh_msgs().


Get info about the context. Corresponds to dc_get_info().

Returns an object with the following properties:

  • arch
  • blobdir
  • configured_mvbox_folder
  • configured_sentbox_folder
  • database_dir
  • database_version
  • deltachat_core_version
  • display_name
  • e2ee_enabled
  • entered_account_settings
  • fingerprint
  • folders_configured
  • inbox_watch
  • is_configured
  • mdns_enabled
  • messages_in_contact_requests
  • mvbox_move
  • mvbox_watch
  • number_of_chat_messages
  • number_of_chats
  • number_of_contacts
  • private_key_count
  • public_key_count
  • sentbox_watch
  • sqlite_thread_safe
  • sqlite_version
  • used_account_settings


Get a single Message object. Corresponds to dc_get_msg().


Get the total number of messages in a chat. Corresponds to dc_get_msg_cnt().


Get an informational text for a single message. Corresponds to dc_get_msg_info().

dc.getNextMediaMessage(messageId, msgType1, msgType2, msgType3)

Get next message of the same type. Corresponds to dc_get_next_media().

dc.getPreviousMediaMessage(messageId, msgType1, msgType2, msgType3)

Get previous message of the same type. Corresponds to dc_get_next_media().


Get QR code text that will offer a secure-join verification. Corresponds to dc_get_securejoin_qr().


Returns an array of starred messages.


Static method. Returns a stripped version of dc.getInfo() which only contains stats of the software and the system and no user related data. Useful when you want to grab version numbers. It should be fast, since no opening of database or configuring is required.

dc.importExport(what, param1, param2)

Import/export things. Corresponds to dc_imex().


Check if there is a backup file. Corresponds to dc_imex_has_backup().


Initiate Autocrypt setup transfer. Corresponds to dc_initiate_key_transfer().

  • callback (function, required) Called with an error as first argument (or null) and the setup code as second argument if no error occured.


Check if the context is already configured. Corresponds to dc_is_configured().

dc.isContactInChat(chatId, contactId)

Check if a given contact id is a member of a group chat. Corresponds to dc_is_contact_in_chat().


Check if the context database is open. Corresponds to dc_is_open().


Join an out-of-band-verification initiated on another device with dc.getSecurejoinQrCode(). Corresponds to dc_join_securejoin().


Mark all messages in a chat as noticed. Corresponds to dc_marknoticed_chat().


Same as dc.markNoticedChat() but for all chats. Corresponds to dc_marknoticed_all_chats().


Returns true if an e-mail address belongs to a known and unblocked contact, otherwise false. Corresponds to dc_lookup_contact_id_by_addr().


Mark all messages sent by the given contact as noticed. Corresponds to dc_marknoticed_contact().


Mark a message as seen, updates the IMAP state and sends MDNs. Corresponds to dc_markseen_msgs().


Static method. Returns true if addr maybe is a valid e-mail address, otherwise false. Corresponds to dc_may_be_valid_addr().


Called as a hint to deltachat-core-rust that the network is available again, to trigger pending messages to be sent. Corresponds to dc_maybe_network().


Create a new Message object. Corresponds to dc_msg_new(). The viewType parameter is optional and defaults to DC_MSG_TEXT. Pick from one of the following values:

  • DC_MSG_VOICE[cwd], callback)

Opens the underlying database.

  • cwd (string, optional) Path to working directory, defaults to current working directory.
  • callback (function, required) Called with an error if the database could not be opened.

dc.removeContactFromChat(chatId, contactId)

Remove a member from a group. Corresponds to dc_remove_contact_from_chat().

dc.searchMessages(chatId, query)

Search messages containing the given query string. Corresponds to dc_search_msgs().

dc.sendMessage(chatId, msg)

Send a message of any type to a chat. Corresponds to dc_send_msg(). The msg parameter can either be a string or a Message object.

dc.setChatName(chatId, name)

Set group name. Corresponds to dc_set_chat_name().

dc.setChatProfileImage(chatId, image)

Set group profile image. Corresponds to dc_set_chat_profile_image().

dc.setConfig(key, value)

Configure the context. Corresponds to dc_set_config().

dc.setStockTranslation(index, text)

Set stock string. Corresponds to dc_set_stock_translation().

dc.setDraft(chatId, message)

Save a draft for a chat in the database. Corresponds to dc_set_draft().

dc.starMessages(messageIds, star)

Star/unstar messages. Corresponds to dc_star_msgs().

class Chat

An object representing a single chat in memory.


Get archived state. Corresponds to dc_chat_get_archived().


Get a color for the chat. Corresponds to dc_chat_get_color().


Get chat id. Corresponds to dc_chat_get_id().


Get name of a chat. Corresponds to dc_chat_get_name().


Get the chat's profile image. Corresponds to dc_chat_get_profile_image().


Get a subtitle for a chat. Corresponds to dc_chat_get_subtitle().


Get chat type. Corresponds to dc_chat_get_type().


Check if a chat is a self talk. Corresponds to dc_chat_is_self_talk().


Check if a chat is still unpromoted. Corresponds to dc_chat_is_unpromoted().


Check if a chat is verified. Corresponds to dc_chat_is_verified().


Returns the object state as a JavaScript serializable object.

class ChatList

An object representing a single chatlist in memory.


Get a single chat id of a chatlist. Corresponds to dc_chatlist_get_chat_id().


Get the number of chats in a chatlist. Corresponds to dc_chatlist_get_cnt().


Get a single message id of a chatlist. Corresponds to dc_chatlist_get_msg_id().

list.getSummary(index, chat)

Get a summary for a chatlist index. Returns a Lot object. Corresponds to dc_chatlist_get_summary().

class Contact

An object representing a single contact in memory.


Get email address. Corresponds to dc_contact_().


Get a color for the contact. Corresponds to dc_chat_get_color().


Get display name. Corresponds to dc_contact_get_display_name().


Get the part of the name before the first space. Corresponds to dc_contact_get_first_name().


Get the id of the contact. Corresponds to dc_contact_get_id().


Get the name of the contact. Corresponds to dc_contact_get_name().


Get a summary of name and address. Corresponds to dc_contact_get_name_n_addr().


Get the profile image of a contact. Corresponds to dc_contact_get_profile_image().


Check if a contact is blocked. Corresponds to dc_contact_is_blocked().


Check if a contact is verified. Corresponds to dc_contact_is_verified().


Returns the object state as a JavaScript serializable object.

class Lot

An object containing a set of values in memory.


Get the associated id. Corresponds to dc_lot_get_id().


Get the associated state. Corresponds to dc_lot_get_state().


Get first string. Corresponds to dc_lot_get_text1().


Get the meaning of the first string. Corresponds to dc_lot_get_text1_meaning().


Get the second string. Corresponds to dc_lot_get_text2().


Get the associated timestamp. Corresponds to dc_lot_get_timestamp().


Returns the object state as a JavaScript serializable object.

class Message

An object representing a single message in memory.


Get the id of the chat the message belongs to. Corresponds to dc_msg_get_chat_id().


Get duration of audio of video. Corresponds to dc_msg_get_duration().


Find out full path, file name and extension of the file associated with a message. Corresponds to dc_msg_get_file().


Get the size of the file. Corresponds to dc_msg_get_filebytes().


Get mime type of the file. Corresponds to dc_msg_get_filemime().


Get base file name without path. Corresponds to dc_msg_get_filename().


Get the id of the contact that wrote the message. Corresponds to dc_msg_get_from_id().


Get height of image or video. Corresponds to dc_msg_get_height().


Get the id of the message. Corresponds to dc_msg_get_id().


Get message receive time. Corresponds to dc_msg_get_received_timestamp().


Get first characters of the setup code. Corresponds to dc_msg_get_setupcodebegin().


Check if a padlock should be shown beside the message. Corresponds to dc_msg_get_showpadlock().


Get message time used for sorting. Corresponds to dc_msg_get_sort_timestamp().


Get the state of the message. Returns a MessageState object. Corresponds to dc_msg_get_state().


Get a summary of a message. Returns a Lot object. Corresponds to dc_msg_get_summary().


Get a message summary as a single line of text. Corresponds to `dc_msg_get_summarytext().


Get the text of the message. Corresponds to dc_msg_get_text().


Get message sending time. Corresponds to dc_msg_get_timestamp().


Get the view type of the message. Returns a MessageViewType object. Corresponds to dc_msg_get_viewtype().


Get the width of image or video. Corresponds to dc_msg_get_width().


Check if a message has a deviating timestamp. Corresponds to dc_msg_has_deviating_timestamp().


Check if a message has a location. Corresponds to dc_msg_has_location().


Check if the message belongs to the virtual dead drop chat.


Check if the message is a forwarded message. Corresponds to dc_msg_is_forwarded().


Check if a message is still in creation. Corresponds to dc_msg_is_increation().


Check if the message is an informational message, created by the device or by another user. Corresponds to dc_msg_is_info().


Check if a message was sent successfully. Corresponds to dc_msg_is_sent().


Check if the message is an Autocrypt setup message. Corresponds to dc_msg_is_setupmessage().


Check if a message is starred. Corresponds to dc_msg_is_starred().

msg.latefilingMediasize(width, height, duration)

Late filing information to a message. Corresponds to dc_msg_latefiling_mediasize().

msg.setDimension(width, height)

Set the dimensions associated with a message. Corresponds to dc_msg_set_dimension(). Returns this so you can do chained commands.


Set the duration assocated with the message object. Corresponds to dc_msg_set_duration(). Returns this so you can do chained commands.

msg.setLocation(latitude, longitude)

Set the location of a message. Corresponds to dc_msg_set_location(). Returns this so you can do chained commands.

msg.setFile(file, mime)

Set the file assocated with the message object. Corresponds to dc_msg_set_file(). Returns this so you can do chained commands.


Set the test of a message object. Corresponds to dc_msg_set_text(). Returns this so you can do chained commands.


Returns the object state as a JavaScript serializable object.

class MessageState

An object representing a Message state.


Message state is DC_STATE_UNDEFINED.


Message state is DC_STATE_IN_FRESH.


Message state is DC_STATE_IN_NOTICED.


Message state is DC_STATE_IN_SEEN.


Message state is DC_STATE_OUT_PENDING.


Message state is DC_STATE_OUT_FAILED.


Message state is DC_STATE_OUT_DELIVERED.


Message state is DC_STATE_OUT_MDN_RCVD.


Internal state property.

class MessageViewType

An object representing a Message view type.


Message type is DC_MSG_TEXT.


Message type has DC_MSG_IMAGE bits set.


Message type is DC_MSG_GIF.


Message type has DC_MSG_AUDIO bits set.


Message type is DC_MSG_VOICE.


Message type has DC_MSG_VIDEO bits set.


Message type is DC_MSG_FILE.


Internal viewType property.


DeltaChat is an EventEmitter and emits the following events.

Event Description Arguments
ready DeltaChat is ready -
DC_EVENT_INFO Info string (info)
DC_EVENT_SMTP_CONNECTED Info string (info)
DC_EVENT_IMAP_CONNECTED Info string (info)
DC_EVENT_WARNING Warning string (warning)
DC_EVENT_ERROR Error string (error)
DC_EVENT_ERROR_NETWORK Network error (first, error)
DC_EVENT_MSGS_CHANGED Messages or chats changed (chatId, msgId)
DC_EVENT_INCOMING_MSG There is a fresh message (chatId, msgId)
DC_EVENT_MSG_DELIVERED Message was sent successfully (chatId, msgId)
DC_EVENT_MSG_FAILED Message could not be sent (chatId, msgId)
DC_EVENT_MSG_READ Message read by the receiver (chatId, msgId)
DC_EVENT_CHAT_MODIFIED Chat modified (chatId)
DC_EVENT_CONTACTS_CHANGED Contact changed (contactId)
DC_EVENT_LOCATION_CHANGED Location changed for a contact (contactId)
DC_EVENT_CONFIGURE_PROGRESS Configuration progress (progress)
DC_EVENT_IMEX_PROGRESS Import/export progress (progress)
DC_EVENT_IMEX_FILE_WRITTEN A file has been exported (fileName)
DC_EVENT_SECUREJOIN_INVITER_PROGRESS Progress of a secure-join handshake (contactId, progress)
DC_EVENT_SECUREJOIN_JOINER_PROGRESS Progress of a secure-join handshake (contactId, progress)
ALL All events from deltachat-core (event, data1, data2)


Tests and Coverage

Running npm test ends with showing a code coverage report, which is produced by nyc.

test output

The coverage report from nyc in the console is rather limited. To get a more detailed coverage report you can run npm run coverage-html-report. This will produce a html report from the nyc data and display it in a browser on your local machine.

On Travis the coverage report is also passed to coveralls.

To run the integration tests you need to set the DC_ADDR and DC_MAIL_PW environment variables. E.g.:

$ export
$ export DC_MAIL_PW=myp4ssw0rD
$ npm run test-integration


We have the following scripts for building, testing and coverage:

  • npm run coverage Creates a coverage report and passes it to coveralls. Only done by Travis.
  • npm run coverage-html-report Generates a html report from the coverage data and opens it in a browser on the local machine.
  • npm run generate-constants Generates constants.js and events.js based on the deltachat-core-rust/deltachat-ffi/deltachat.h header file.
  • npm install After dependencies are installed, runs node-gyp-build to see if the native code needs to be rebuilt.
  • npm run rebuild-all Rebuilds all code.
  • npm run rebuild-core Rebuilds code in deltachat-core-rust.
  • npm run rebuild-bindings Rebuilds the bindings and links with deltachat-core-rust.
  • npm run node-gyp-build Tries to load prebuilts and falls back to rebuilding the code.
  • npm run prebuild Builds prebuilt binary to prebuilds/$PLATFORM-$ARCH. Copies deltachat.dll from deltachat-core-rust for windows.
  • npm run download-prebuilds Downloads all prebuilt binaries from github before npm publish.
  • npm run submodule Updates the deltachat-core-rust submodule.
  • npm test Runs standard and then the tests in test/index.js.
  • npm run test-integration Runs the integration tests.
  • npm run hallmark Runs hallmark on all markdown files.


The following steps are needed to make a release:

  1. Update (and run npm run hallmark to adjust markdown)
  2. Bump version number, e.g. npm version minor, which will update version number in package.json, commit the changes and tag the commit
  3. Push to github, e.g. git push origin master && git push origin --tags
  4. Wait until Travis and AppVeyor have finished and uploaded prebuilt binaries to GitHub
  5. npm run download-prebuilds to download prebuilt binaries from GitHub.
  6. npm publish


Licensed under GPL-3.0-or-later, see LICENSE file for details.

Copyright © 2018 DeltaChat contributors.

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 3 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, see