code:
=========================================
|||   RimJobWorld Community Project   |||
=========================================

Special thanks to

Void Main				Original Author

UnlimitedHugs			HugsLib mod library for Rimworld
pardeike				Harmony library
Fluffy					Architecture Sense mod DLL

Loverslab				Housing this mod

Skystreet				Saved A16 version from nexus oblivion
nethrez1m				HugsLib / RimWorldChildren fixes
prkr_jmsn				A17 compatibility, Genital injection, sounds, filth
Goddifist				Ideas
shark510				Textures, testing
Soronarr				Surgery recipes, monstergirls
semigimp				General coding
AngleWyrm				Textures
Alanetsai				Chinese traditional translations
nizhuan-jjr				Chinese simplified translations, general coding, bugsfix,
						whore system, broken body system, balancing, testing, textures,
						previews, etc.
g0ring					Coding idea, bugfix
StarlightG				Coding idea, bugfix
SuperHotSausage			Coding, stuff
Sidfu					Coding, XML modding
NEPH					Graphics & textures, testing, Korean translation
hogehoge1942			Coding, Japanese translation
Ed86					Coding
TheSleeplessSorclock	Coding
asdiky					Russian translation
exoxe					Korean translation
Atrer					Coding
Zaltys					Coding
SlicedBread				Textures

And anyone we might have missed.
add your self

license: mit


code:
-The transgender thoughts sometimes disappear if you perform a chain of sex operations on the same pawn.
Probably some oversight in algorithm that gives thoughts on transition (some underthought chaining of effects).
Fix somewhere in the future.

-Whores with untended diseases (flu, herpes, warts) will try hookup and may succeed but the job will get cancelled shortly afterwards resulting in message spam.
Currently added different message to notify players of problem.

-Genital helper is shit. It does not account for later added animal dicks. has_<x> methods are fucking runtime regex searches


code:
CORE:

add/change passive whoring colonist search(like cp) -> colonist know who is whore, and try to use them? may get refused by whore?
add nymph lord ai, so nymphs can behave as visitors
add sex addiction to demonic parts?
add insects dragging pawns to hives
gene inheritance for insect ovis

workgivers(aka manual control):
-workgiver for sex with humpshrooms, increasing their growth by 1 day, causing addiction, temp? humpshroom-penis futa?
-workgiver(auto, cleaning) to collect cum

add recipe to make food from cum?
add female cum?

add some sort of right clicking sub menu:
-change parts stats(w/o operation): tentacles, slime, bionic parts
-designate breeding pair(through relations?)

rework genital system, so it only have vag,penis,breast,anus (with comp?) storing name, severity(size?) of part
probably also rework surgeries to support those
add variable parts growth (until teen? adult?), degradation/stretching
rework sex satisfaction system(based on parts size/difference? traits/quirks etc)

integrate milkable colonists with sizes support and operations? to change milk type(w gitterworld med?)

BDSM:
-make ropes and other generic gear, that is "locked" but not with hololock unique keys - normal keys made of steel, etc
-piercing?
-blindfolds?
-vibrators?

Multiplayer:
-figure out predictable seeds instead of syncmethod's

maybe:
add support for other pregnancy mods
more sex related incidents?
backstories: cowgirl, etc

never?
-make interactive COC like sex/stories
RatherNot (Code)
We need Pawn Sexualization Request: like Pawn Generation Request, but for generating RJW things
Current approach missing any kind of flexibility
In can be useful for race support to: instead placing checks directly in generator you can place limitations on generator in request

older stuff
TO DO:
Add new body part groups for the bondage gear (specifically a genitals group for the CB and a jaw or mouth group for the gag, the mouth group that's already in the game won't work I'm pretty sure)
Once that (^^^) is done make it so that the groups are automatically blocked by the gear, like a more robust version of the blocks_genitals flag
Add more thoughts after sex about e.g. partner's dick size and sex skill
Add chance for sex/fap with a peg dick to produce splinters

TO DO EVENTUALLY (AKA NEVER):
Improve detection of genital harvest vs amputation
  - (Maybe) Make it so that downgrading a pawn is considered harvesting

OTHER RANDOM/HALF-BAKED IDEAS:
Add some random dialogues for rapes, lovins, etc.
Strap prisoners to their beds
Sex addiction
  - Reduces satisfaction from sex
  - Should only affect nymphomaniacs?

Traits?:
Low Self Esteem (just another pessimist trait)

Dom/Sub

Mindbroken (raped so much that they are at a permanent max happiness, but are worth nothing more than just hauling and cleaning)

Branded, this pawn is branded a cow/animal fucker/prostitute/rapist, whatever his/her extra curricular is comes with a negative opinions so they are pretty much never liked?


code:
/client/target
/target
/server/target
/server/tor

repo_name: deltanedas/omail

path: .gitignore

license: unknown


code:
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3

[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"

[[package]]
name = "autotools"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8138adefca3e5d2e73bfba83bd6eeaf904b26a7ac1b4a19892cfe16cc7e1701"
dependencies = [
 "cc",
]

[[package]]
name = "base32"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa"

[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
 "generic-array",
]

[[package]]
name = "block-buffer"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
dependencies = [
 "generic-array",
]

[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"

[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"

[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"

[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
 "libc",
 "num-integer",
 "num-traits",
 "time",
 "winapi",
]

[[package]]
name = "cpufeatures"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
dependencies = [
 "libc",
]

[[package]]
name = "crypto-common"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
dependencies = [
 "generic-array",
 "typenum",
]

[[package]]
name = "curve25519-dalek"
version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0"
dependencies = [
 "byteorder",
 "digest 0.9.0",
 "rand_core 0.5.1",
 "subtle",
 "zeroize",
]

[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
 "generic-array",
]

[[package]]
name = "digest"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
dependencies = [
 "block-buffer 0.10.2",
 "crypto-common",
]

[[package]]
name = "ed25519"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eed12bbf7b5312f8da1c2722bc06d8c6b12c2d86a7fb35a194c7f3e6fc2bbe39"
dependencies = [
 "signature",
]

[[package]]
name = "ed25519-dalek"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
dependencies = [
 "curve25519-dalek",
 "ed25519",
 "rand 0.7.3",
 "serde",
 "sha2",
 "zeroize",
]

[[package]]
name = "fs_extra"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"

[[package]]
name = "generic-array"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803"
dependencies = [
 "typenum",
 "version_check",
]

[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
 "cfg-if",
 "libc",
 "wasi 0.9.0+wasi-snapshot-preview1",
]

[[package]]
name = "getrandom"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
dependencies = [
 "cfg-if",
 "libc",
 "wasi 0.10.2+wasi-snapshot-preview1",
]

[[package]]
name = "keccak"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"

[[package]]
name = "libc"
version = "0.2.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"

[[package]]
name = "libtor"
version = "46.9.0+0.4.6.x"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18ca40c5090fd84877853f509dce8f906922e6c6fb0be12f4b61f6116710d457"
dependencies = [
 "libtor-derive",
 "libtor-sys",
 "log",
 "rand 0.8.5",
 "sha1",
]

[[package]]
name = "libtor-derive"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "177781b25e83853831c5af66320ceaf5e456e1b6d533426fcd9c7544b5543043"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "libtor-sys"
version = "46.9.1+0.4.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52bf218e9764d77c16b77b9a26f219c5302bf7be010fd82aba63b019dea41fea"
dependencies = [
 "autotools",
 "cc",
 "fs_extra",
 "libz-sys",
 "openssl-sys",
]

[[package]]
name = "libz-sys"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f35facd4a5673cb5a48822be2be1d4236c1c99cb4113cab7061ac720d5bf859"
dependencies = [
 "cc",
 "libc",
 "pkg-config",
 "vcpkg",
]

[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
 "cfg-if",
]

[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
 "autocfg",
 "num-traits",
]

[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
 "autocfg",
]

[[package]]
name = "omail"
version = "1.0.0"
dependencies = [
 "base32",
 "byteorder",
 "chrono",
 "ed25519-dalek",
 "libtor",
 "sha3",
]

[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"

[[package]]
name = "openssl-sys"
version = "0.9.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
dependencies = [
 "autocfg",
 "cc",
 "libc",
 "pkg-config",
 "vcpkg",
]

[[package]]
name = "pkg-config"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"

[[package]]
name = "ppv-lite86"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"

[[package]]
name = "proc-macro2"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
 "unicode-xid",
]

[[package]]
name = "quote"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
dependencies = [
 "proc-macro2",
]

[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
 "getrandom 0.1.16",
 "libc",
 "rand_chacha 0.2.2",
 "rand_core 0.5.1",
 "rand_hc",
]

[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
 "libc",
 "rand_chacha 0.3.1",
 "rand_core 0.6.3",
]

[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
 "ppv-lite86",
 "rand_core 0.5.1",
]

[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
 "ppv-lite86",
 "rand_core 0.6.3",
]

[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
 "getrandom 0.1.16",
]

[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
 "getrandom 0.2.5",
]

[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
 "rand_core 0.5.1",
]

[[package]]
name = "serde"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"

[[package]]
name = "sha1"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770"
dependencies = [
 "sha1_smol",
]

[[package]]
name = "sha1_smol"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"

[[package]]
name = "sha2"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
dependencies = [
 "block-buffer 0.9.0",
 "cfg-if",
 "cpufeatures",
 "digest 0.9.0",
 "opaque-debug",
]

[[package]]
name = "sha3"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "881bf8156c87b6301fc5ca6b27f11eeb2761224c7081e69b409d5a1951a70c86"
dependencies = [
 "digest 0.10.3",
 "keccak",
]

[[package]]
name = "signature"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4"

[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"

[[package]]
name = "syn"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
 "proc-macro2",
 "quote",
 "unicode-xid",
]

[[package]]
name = "synstructure"
version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
 "unicode-xid",
]

[[package]]
name = "time"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
dependencies = [
 "libc",
 "winapi",
]

[[package]]
name = "typenum"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"

[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"

[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"

[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"

[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"

[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"

[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
 "winapi-i686-pc-windows-gnu",
 "winapi-x86_64-pc-windows-gnu",
]

[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"

[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

[[package]]
name = "zeroize"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
dependencies = [
 "zeroize_derive",
]

[[package]]
name = "zeroize_derive"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
 "synstructure",
]


code:
[package]
name = "omail"
version = "1.0.0"
edition = "2021"

[dependencies]
base32 = "0.4"
byteorder = "1.4"
chrono = "0.4"
ed25519-dalek = "1.0"
libtor = "46"
sha3 = "0.10"


code:
# omail

Private, secure and optionally anonymous mail over TOR.

# How to run

Compile: `cargo build --release`

Move `target/release/omail_server` somewhere nice and run it forever.

Move `target/release/omail_client` somewhere nice and run it whenever you want to send something.

# Multiple addresses

To have multiple addresses just add more hidden services and point them to the same interal port.

To send from a certain address use `omail_client --from address_name`, where `address_name` is in `<omail_server>/tor/hidden_service/`.

# test your server

[omail://echoj3zv2e4vsl2drwk36bwajbqpsapwcw2rlo6tjpdhgihnbstiiqyd.onion](test your server by sending something here)


code:
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3

[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
 "hermit-abi",
 "libc",
 "winapi",
]

[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"

[[package]]
name = "autotools"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8138adefca3e5d2e73bfba83bd6eeaf904b26a7ac1b4a19892cfe16cc7e1701"
dependencies = [
 "cc",
]

[[package]]
name = "base32"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa"

[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"

[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
 "generic-array",
]

[[package]]
name = "block-buffer"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
dependencies = [
 "generic-array",
]

[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"

[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"

[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"

[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
 "libc",
 "num-integer",
 "num-traits",
 "time",
 "winapi",
]

[[package]]
name = "clap"
version = "3.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123"
dependencies = [
 "atty",
 "bitflags",
 "clap_derive",
 "indexmap",
 "lazy_static",
 "os_str_bytes",
 "strsim",
 "termcolor",
 "textwrap",
]

[[package]]
name = "clap_derive"
version = "3.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da95d038ede1a964ce99f49cbe27a7fb538d1da595e4b4f70b8c8f338d17bf16"
dependencies = [
 "heck",
 "proc-macro-error",
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "cpufeatures"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
dependencies = [
 "libc",
]

[[package]]
name = "crypto-common"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
dependencies = [
 "generic-array",
 "typenum",
]

[[package]]
name = "curve25519-dalek"
version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0"
dependencies = [
 "byteorder",
 "digest 0.9.0",
 "rand_core 0.5.1",
 "subtle",
 "zeroize",
]

[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
 "generic-array",
]

[[package]]
name = "digest"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
dependencies = [
 "block-buffer 0.10.2",
 "crypto-common",
]

[[package]]
name = "ed25519"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eed12bbf7b5312f8da1c2722bc06d8c6b12c2d86a7fb35a194c7f3e6fc2bbe39"
dependencies = [
 "signature",
]

[[package]]
name = "ed25519-dalek"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
dependencies = [
 "curve25519-dalek",
 "ed25519",
 "rand 0.7.3",
 "serde",
 "sha2",
 "zeroize",
]

[[package]]
name = "fs_extra"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"

[[package]]
name = "generic-array"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803"
dependencies = [
 "typenum",
 "version_check",
]

[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
 "cfg-if",
 "libc",
 "wasi 0.9.0+wasi-snapshot-preview1",
]

[[package]]
name = "getrandom"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
dependencies = [
 "cfg-if",
 "libc",
 "wasi 0.10.2+wasi-snapshot-preview1",
]

[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"

[[package]]
name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"

[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
 "libc",
]

[[package]]
name = "indexmap"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
 "autocfg",
 "hashbrown",
]

[[package]]
name = "keccak"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"

[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"

[[package]]
name = "libc"
version = "0.2.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"

[[package]]
name = "libtor"
version = "46.9.0+0.4.6.x"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18ca40c5090fd84877853f509dce8f906922e6c6fb0be12f4b61f6116710d457"
dependencies = [
 "libtor-derive",
 "libtor-sys",
 "log",
 "rand 0.8.5",
 "sha1",
]

[[package]]
name = "libtor-derive"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "177781b25e83853831c5af66320ceaf5e456e1b6d533426fcd9c7544b5543043"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "libtor-sys"
version = "46.9.1+0.4.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52bf218e9764d77c16b77b9a26f219c5302bf7be010fd82aba63b019dea41fea"
dependencies = [
 "autotools",
 "cc",
 "fs_extra",
 "libz-sys",
 "openssl-sys",
]

[[package]]
name = "libz-sys"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f35facd4a5673cb5a48822be2be1d4236c1c99cb4113cab7061ac720d5bf859"
dependencies = [
 "cc",
 "libc",
 "pkg-config",
 "vcpkg",
]

[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
 "cfg-if",
]

[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"

[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
 "autocfg",
 "num-traits",
]

[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
 "autocfg",
]

[[package]]
name = "omail"
version = "1.0.0"
dependencies = [
 "base32",
 "byteorder",
 "chrono",
 "ed25519-dalek",
 "libtor",
 "sha3",
]

[[package]]
name = "omail_client"
version = "0.1.0"
dependencies = [
 "byteorder",
 "clap",
 "omail",
 "socks",
]

[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"

[[package]]
name = "openssl-sys"
version = "0.9.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
dependencies = [
 "autocfg",
 "cc",
 "libc",
 "pkg-config",
 "vcpkg",
]

[[package]]
name = "os_str_bytes"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
 "memchr",
]

[[package]]
name = "pkg-config"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"

[[package]]
name = "ppv-lite86"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"

[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
 "proc-macro-error-attr",
 "proc-macro2",
 "quote",
 "syn",
 "version_check",
]

[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
 "proc-macro2",
 "quote",
 "version_check",
]

[[package]]
name = "proc-macro2"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
 "unicode-xid",
]

[[package]]
name = "quote"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
dependencies = [
 "proc-macro2",
]

[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
 "getrandom 0.1.16",
 "libc",
 "rand_chacha 0.2.2",
 "rand_core 0.5.1",
 "rand_hc",
]

[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
 "libc",
 "rand_chacha 0.3.1",
 "rand_core 0.6.3",
]

[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
 "ppv-lite86",
 "rand_core 0.5.1",
]

[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
 "ppv-lite86",
 "rand_core 0.6.3",
]

[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
 "getrandom 0.1.16",
]

[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
 "getrandom 0.2.5",
]

[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
 "rand_core 0.5.1",
]

[[package]]
name = "serde"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"

[[package]]
name = "sha1"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770"
dependencies = [
 "sha1_smol",
]

[[package]]
name = "sha1_smol"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"

[[package]]
name = "sha2"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
dependencies = [
 "block-buffer 0.9.0",
 "cfg-if",
 "cpufeatures",
 "digest 0.9.0",
 "opaque-debug",
]

[[package]]
name = "sha3"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "881bf8156c87b6301fc5ca6b27f11eeb2761224c7081e69b409d5a1951a70c86"
dependencies = [
 "digest 0.10.3",
 "keccak",
]

[[package]]
name = "signature"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4"

[[package]]
name = "socks"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c3dbbd9ae980613c6dd8e28a9407b50509d3803b57624d5dfe8315218cd58b"
dependencies = [
 "byteorder",
 "libc",
 "winapi",
]

[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"

[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"

[[package]]
name = "syn"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
 "proc-macro2",
 "quote",
 "unicode-xid",
]

[[package]]
name = "synstructure"
version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
 "unicode-xid",
]

[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
 "winapi-util",
]

[[package]]
name = "textwrap"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"

[[package]]
name = "time"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
dependencies = [
 "libc",
 "winapi",
]

[[package]]
name = "typenum"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"

[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"

[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"

[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"

[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"

[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"

[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
 "winapi-i686-pc-windows-gnu",
 "winapi-x86_64-pc-windows-gnu",
]

[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"

[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
 "winapi",
]

[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

[[package]]
name = "zeroize"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
dependencies = [
 "zeroize_derive",
]

[[package]]
name = "zeroize_derive"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
 "synstructure",
]


code:
[package]
name = "omail_client"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
byteorder = "*"
clap = {version = "3.1", features = ["derive"]}
omail = {path = ".."}
socks = "*"


code:
use std::io::{Read, Seek, SeekFrom};
use std::fs::File;

use byteorder::ReadBytesExt;
use clap::*;
use omail::{addr::*, *};
use socks::Socks5Stream;

/// Send a message to an omail server
#[derive(Parser)]
#[clap(author, version, about)]
struct Args {
	/// Name of the key to sign the message with
	#[clap(short, long)]
	from: Option<String>,
	/// Subject of the message
	#[clap(short, long)]
	subject: String,
	/// Onion v3 address to send to
	dest: String,
	/// Body of the message
	body: String
}

fn main() {
	let args = Args::parse();

	let message = Message::new()
		.with_subject(args.subject)
		.with_text_body(args.body);
	let keypair = match args.from {
		Some(name) => Some(read_keypair("../server/tor", &name)
			.expect("Failed to read keypair")),
		None => None
	};

	let addr = format!("{}:{}", args.dest, DEFAULT_PORT);
	let proxy_addr = format!("127.0.0.1:{}", SOCKS_PORT);
	let mut sock = Socks5Stream::connect(proxy_addr, addr.as_str())
		.expect("Failed to connect");
	println!("[*] Connected");

	message.send(&mut sock, keypair.as_ref())
		.expect("Failed to send message");
	println!("[*] Sent");
	if let Some(keypair) = keypair {
		println!("[*] Sender: {}", onion_from_key(&keypair.public));
		println!("[*] Secret: {:?}", keypair.secret.to_bytes());
		let signature = keypair.sign(b"amogus");
		println!("[*] Verify: {:?}", keypair.verify(b"amogus", &signature));
	}

	let response = sock.read_u8()
		.expect("Failed to read response");
	println!("[*] {}", match response {
		0 => "Success!",
		1 => "Malformed mail",
		2 => "Attachments too large",
		3 => "Body too large",
		4 => "Invalid sender",
		5 => "Invalid signature",
		6 => "Invalid sent timestamp",
		_ => "(Unknown response)"
	});
}

fn read_keypair(dir: &str, name: &str) -> Option<Keypair> {
	let mut bytes = [0; KEYPAIR_LENGTH];
	let mut file = File::open(format!("{}/hidden_service/{}/hs_ed25519_secret_key", dir, name)).ok()?;
	file.seek(SeekFrom::Start(32)).ok()?;
	file.read_exact(&mut bytes[0..SECRET_KEY_LENGTH]).ok()?;
	let mut file = File::open(format!("{}/hidden_service/{}/hs_ed25519_public_key", dir, name)).ok()?;
	file.seek(SeekFrom::Start(32)).ok()?;
	file.read_exact(&mut bytes[SECRET_KEY_LENGTH..]).ok()?;
	Some(Keypair::from_bytes(&bytes).ok()?)
}


code:
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3

[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"

[[package]]
name = "autotools"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8138adefca3e5d2e73bfba83bd6eeaf904b26a7ac1b4a19892cfe16cc7e1701"
dependencies = [
 "cc",
]

[[package]]
name = "base32"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa"

[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
 "generic-array",
]

[[package]]
name = "block-buffer"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
dependencies = [
 "generic-array",
]

[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"

[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"

[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"

[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
 "libc",
 "num-integer",
 "num-traits",
 "time",
 "winapi",
]

[[package]]
name = "cpufeatures"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
dependencies = [
 "libc",
]

[[package]]
name = "crypto-common"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
dependencies = [
 "generic-array",
 "typenum",
]

[[package]]
name = "curve25519-dalek"
version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0"
dependencies = [
 "byteorder",
 "digest 0.9.0",
 "rand_core 0.5.1",
 "subtle",
 "zeroize",
]

[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
 "generic-array",
]

[[package]]
name = "digest"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
dependencies = [
 "block-buffer 0.10.2",
 "crypto-common",
]

[[package]]
name = "ed25519"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eed12bbf7b5312f8da1c2722bc06d8c6b12c2d86a7fb35a194c7f3e6fc2bbe39"
dependencies = [
 "signature",
]

[[package]]
name = "ed25519-dalek"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
dependencies = [
 "curve25519-dalek",
 "ed25519",
 "rand 0.7.3",
 "serde",
 "sha2",
 "zeroize",
]

[[package]]
name = "fs_extra"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"

[[package]]
name = "generic-array"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803"
dependencies = [
 "typenum",
 "version_check",
]

[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
 "cfg-if",
 "libc",
 "wasi 0.9.0+wasi-snapshot-preview1",
]

[[package]]
name = "getrandom"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
dependencies = [
 "cfg-if",
 "libc",
 "wasi 0.10.2+wasi-snapshot-preview1",
]

[[package]]
name = "keccak"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"

[[package]]
name = "libc"
version = "0.2.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"

[[package]]
name = "libtor"
version = "46.9.0+0.4.6.x"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18ca40c5090fd84877853f509dce8f906922e6c6fb0be12f4b61f6116710d457"
dependencies = [
 "libtor-derive",
 "libtor-sys",
 "log",
 "rand 0.8.5",
 "sha1",
]

[[package]]
name = "libtor-derive"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "177781b25e83853831c5af66320ceaf5e456e1b6d533426fcd9c7544b5543043"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "libtor-sys"
version = "46.9.1+0.4.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52bf218e9764d77c16b77b9a26f219c5302bf7be010fd82aba63b019dea41fea"
dependencies = [
 "autotools",
 "cc",
 "fs_extra",
 "libz-sys",
 "openssl-sys",
]

[[package]]
name = "libz-sys"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f35facd4a5673cb5a48822be2be1d4236c1c99cb4113cab7061ac720d5bf859"
dependencies = [
 "cc",
 "libc",
 "pkg-config",
 "vcpkg",
]

[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
 "cfg-if",
]

[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
 "autocfg",
 "num-traits",
]

[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
 "autocfg",
]

[[package]]
name = "omail"
version = "1.0.0"
dependencies = [
 "base32",
 "byteorder",
 "chrono",
 "ed25519-dalek",
 "libtor",
 "sha3",
]

[[package]]
name = "omail_server"
version = "0.1.0"
dependencies = [
 "byteorder",
 "libtor",
 "omail",
]

[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"

[[package]]
name = "openssl-sys"
version = "0.9.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
dependencies = [
 "autocfg",
 "cc",
 "libc",
 "pkg-config",
 "vcpkg",
]

[[package]]
name = "pkg-config"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"

[[package]]
name = "ppv-lite86"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"

[[package]]
name = "proc-macro2"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
 "unicode-xid",
]

[[package]]
name = "quote"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
dependencies = [
 "proc-macro2",
]

[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
 "getrandom 0.1.16",
 "libc",
 "rand_chacha 0.2.2",
 "rand_core 0.5.1",
 "rand_hc",
]

[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
 "libc",
 "rand_chacha 0.3.1",
 "rand_core 0.6.3",
]

[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
 "ppv-lite86",
 "rand_core 0.5.1",
]

[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
 "ppv-lite86",
 "rand_core 0.6.3",
]

[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
 "getrandom 0.1.16",
]

[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
 "getrandom 0.2.5",
]

[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
 "rand_core 0.5.1",
]

[[package]]
name = "serde"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"

[[package]]
name = "sha1"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770"
dependencies = [
 "sha1_smol",
]

[[package]]
name = "sha1_smol"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"

[[package]]
name = "sha2"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
dependencies = [
 "block-buffer 0.9.0",
 "cfg-if",
 "cpufeatures",
 "digest 0.9.0",
 "opaque-debug",
]

[[package]]
name = "sha3"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "881bf8156c87b6301fc5ca6b27f11eeb2761224c7081e69b409d5a1951a70c86"
dependencies = [
 "digest 0.10.3",
 "keccak",
]

[[package]]
name = "signature"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4"

[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"

[[package]]
name = "syn"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
 "proc-macro2",
 "quote",
 "unicode-xid",
]

[[package]]
name = "synstructure"
version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
 "unicode-xid",
]

[[package]]
name = "time"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
dependencies = [
 "libc",
 "winapi",
]

[[package]]
name = "typenum"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"

[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"

[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"

[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"

[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"

[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"

[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
 "winapi-i686-pc-windows-gnu",
 "winapi-x86_64-pc-windows-gnu",
]

[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"

[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

[[package]]
name = "zeroize"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
dependencies = [
 "zeroize_derive",
]

[[package]]
name = "zeroize_derive"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
 "synstructure",
]


code:
[package]
name = "omail_server"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
byteorder = "*"
libtor = "46"
omail = {path = ".."}


code:
use std::{
	net::TcpListener,
	process::exit,
	thread
};

use byteorder::WriteBytesExt;
use libtor::*;
use omail::{addr::*, *};

fn main() {
	thread::spawn(start_tor);

	let port = DEFAULT_PORT;
	let addr = format!("127.0.0.1:{}", port);
	println!("[*] Listening on {}", addr);
	let listener = TcpListener::bind(addr)
		.unwrap();

	loop {
		let (mut sock, _addr) = listener.accept()
			.unwrap();
		let limits = Limits {
			data: 5_000_000,
			body: 2_000,
			attachment: 1_000_000,
			attachments: 5
		};
		let message = Message::read(&mut sock, &limits);
		sock.write_u8(0x00); // gaslight

		if let Ok(message) = message {
			let text = String::from_utf8(message.body);
			if let Some(key) = message.sender {
				println!("From: {}", onion_from_key(&key));
			} else {
				println!("Anonymous");
			}
			println!("{}\n{:?}", message.body_type, text);
		} else if let Err(e) = message {
			eprintln!("[!] Error: {:?}", e);
		}
	}
}

fn start_tor() {
	let addresses = vec!["main"];

	let mut tor = Tor::new();
	tor.flag(TorFlag::DataDirectory("tor".into()))
		.flag(TorFlag::SocksPort(SOCKS_PORT));

	// add each address name as a hidden service
	for addr in addresses {
		let dir = format!("tor/hidden_service/{}", addr);
		tor.flag(TorFlag::HiddenServiceDir(dir))
			.flag(TorFlag::HiddenServiceVersion(HiddenServiceVersion::V3))
			.flag(TorFlag::HiddenServicePort(TorAddress::Port(DEFAULT_PORT), None.into()));
	}

	println!("[*] Starting tor");
	tor.start()
		.expect("Failed to start tor");
	exit(0);
}


code:
# onionmail spec

## Message format

### High-level structure

```
Message ::= Headers Body Attachments Signature

Headers ::= Sender Sent Subject
```

### Implementation

All integers are encoded as little-endian.

`Sender ::= string`
	Return address to send replies to.
	Length must be 0 (anonymous) or 35 (raw onion).
	Format for addresses is the base32 decoded version of the address. (without .onion TLD)
	First 32 bytes are the public key, next 2 are the checksum and last is 0x03.
	Without a return address the message is anonymous and cannot be replied to.

`Sent ::= u64`
	Time at which the message was sent.
	Seconds since the UNIX epoch, UTC.

`Subject ::= string`
	Subject of the message, should be provided but is not required.

`Body ::= data`
	The body of the message.
	Should be human-readable, such as text/plain.

`Attachments ::= count: u8, attachments: [Attachment; count]`
	A list of all attached files.

`Attachment ::= name: string, type: string, contents: data`
	An attached file. Has a filename. (Must not contain '/', or be '..' or '.')

`Signature ::= [u8; 64]`
	Signature of the message, required if a return address is given.
	Prevents forgery of messages, but does not ensure that the address is actually running a server.

`string ::= size: u8, bytes: [u8; size]`
	UTF-8 string, size is the length of the encoded bytes.
	Maximum size is 255 bytes.

`data ::= type: string, size: u32, bytes: [u8; size]`
	Some data with a MIME type.

## Sending protocol

Connect to a recipient onion address over port 4605 (default port).

Serialize the message, less signature, to a buffer.

Write buffer length as `u32` and then the buffer.

If a sender is written, sign the buffer and write the signature.

In response one byte will be written, a response code.

Valid response codes:
- 0x00: Success, message sent.
- 0x01: Malformed mail.
- 0x02: Attachments too large, or there are too many.
- 0x03: Body too large.
- 0x04: Invalid sender.
- 0x05: Invalid signature.
- 0x06: Invalid sent timestamp.

A server is allowed to send Success for any message to deter abuse.

# address format
omail://56chars.onion


code:
use base32::Alphabet;
use ed25519_dalek::PublicKey;
use sha3::{Digest, Sha3_256};

#[derive(Debug)]
pub enum Error {
	/// Address not 62 chars long
	InvalidLength,
	/// Address[..56] not valid base32
	InvalidAddr,
	/// Version is not 3
	InvalidVersion,
	/// Checksum is wrong
	InvalidChecksum,
	/// Key can't be decoded
	InvalidKey
}

const ALPHABET: Alphabet = Alphabet::RFC4648 {
	padding: false
};

/// Extract and verify the public key from a .onion address
pub fn key_from_onion(addr: &str) -> Result<PublicKey, Error> {
	if addr.len() != 62 {
		return Err(Error::InvalidLength);
	}

	let bytes = match base32::decode(ALPHABET, &addr[..56]) {
		Some(bytes) => bytes,
		None => return Err(Error::InvalidAddr)
	};

	if bytes[34] != 3 {
		return Err(Error::InvalidVersion);
	}

	let key = PublicKey::from_bytes(&bytes)
		.map_err(|_| Error::InvalidKey)?;

	let mut hash = Sha3_256::new();
	hash.update(b".onion checksum");
	hash.update(key.as_bytes());
	hash.update(b"\x03");
	let checksum = hash.finalize().to_vec();
	if bytes[32..34] != checksum[0..2] {
		return Err(Error::InvalidChecksum);
	}

	// valid checksum and correct version, all good
	Ok(key)
}

pub fn onion_from_key(key: &PublicKey) -> String {
	let mut raw = [0; 35];
	raw[34] = 3;
	raw[0..32].copy_from_slice(key.as_bytes());

	// store the checksum: first 2 bytes of hash
	let mut hash = Sha3_256::new();
	hash.update(b".onion checksum");
	hash.update(key.as_bytes());
	hash.update(b"\x03");
	let checksum = hash.finalize().to_vec();
	raw[32] = checksum[0];
	raw[33] = checksum[1];

	let mut onion = base32::encode(ALPHABET, &raw);
	onion.make_ascii_lowercase();
	onion + ".onion"
}


code:
pub mod addr;
mod util;

use util::*;

use std::io::{Cursor, Read, Result};

use chrono::prelude::Utc;
pub use ed25519_dalek::*;

pub const DEFAULT_PORT: u16 = 4605;
pub const SOCKS_PORT: u16 = 4606;

pub struct Attachment {
	pub name: String,
	pub data_type: String,
	pub data: Vec<u8>
}

impl Attachment {
	pub fn read<R: ReadExtraExt>(r: &mut R, limit: u32) -> Result<Self> {
		let name = r.read_str()?;
		let data_type = r.read_str()?;
		let data = r.read_b32(limit)?;

		Ok(Self {
			name: name,
			data_type: data_type,
			data: data
		})
	}

	pub fn write<W: WriteExtraExt>(&self, w: &mut W) -> Result<()> {
		w.write_str(&self.name)?;
		w.write_str(&self.data_type)?;
		w.write_b32(&self.data)
	}
}

/// Limits for reading a message to prevent memory exhaustion
pub struct Limits {
	/// Maximum network packet size
	pub data: u32,
	/// Maximum message body size
	pub body: u32,
	/// Maximum size of a single attachment's data
	pub attachment: u32,
	/// Maximum number of attachments
	pub attachments: u8
}

/// Message which is encoded according to spec.md
pub struct Message {
	/// Return address to send replies to
	pub sender: Option<PublicKey>,
	/// Seconds since UNIX epoch, UTC
	pub sent: u64,
	/// Subject of the message
	pub subject: String,
	/// Type of the body, such as text/plain
	pub body_type: String,
	/// Body data, should be human readable
	pub body: Vec<u8>,
	/// All attached files
	pub attachments: Vec<Attachment>
}

impl Message {
	pub fn read<R: ReadExtraExt>(r: &mut R, limits: &Limits) -> Result<Self> {
		let bytes = r.read_b32(limits.data)?;
		let mut data = Cursor::new(&bytes);

		let sender = match data.read_u8()? {
			32 => {
				let mut bytes = [0; 32];
				data.read_exact(&mut bytes)?;
				Ok(Some(PublicKey::from_bytes(&bytes)
					.map_err(|_| Error::new(ErrorKind::InvalidData, "Invalid sender"))?))
			},
			0 => Ok(None),
			_ => Err(Error::new(ErrorKind::InvalidData, "Invalid sender length"))
		}?;

		// verify signature
		if let Some(key) = sender {
			let mut signature = [0; 64];
			r.read_exact(&mut signature)?;
			println!("[DEBUG] signature {:?}", signature);
			let signature = Signature::from_bytes(&signature)
				.map_err(|_| Error::new(ErrorKind::InvalidData, "Malformed signature"))?;
			key.verify(&bytes, &signature)
				.map_err(|_| Error::new(ErrorKind::InvalidData, "Incorrect signature"))?;
		}

		let sent = data.read_u64::<LE>()?;
		let subject = data.read_str()?;
		let body_type = data.read_str()?;
		let body = data.read_b32(limits.body)?;

		let count = data.read_u8()?;
		if count > limits.attachments {
			return Err(Error::new(ErrorKind::InvalidData, "Too nany attachments"));
		}

		let mut attachments = Vec::with_capacity(count as usize);
		for _ in 0..count {
			attachments.push(Attachment::read(&mut data, limits.attachment)?);
		}

		Ok(Self {
			sender: sender,
			sent: sent,
			subject: subject,
			body_type: body_type,
			body: body,
			attachments: attachments
		})
	}

	pub fn new() -> Self {
		Self {
			sender: None,
			sent: 0,
			subject: String::new(),
			body_type: String::new(),
			body: vec![],
			attachments: vec![]
		}
	}

	pub fn with_subject(mut self, subject: String) -> Self {
		self.subject = subject;
		self
	}

	pub fn with_text_body(self, text: String) -> Self {
		self.with_body("text/plain".to_owned(), text.into_bytes())
	}

	/// Set a new body
	pub fn with_body(mut self, body_type: String, body: Vec<u8>) -> Self {
		self.body_type = body_type;
		self.body = body;
		self
	}

	/// Attach a file
	pub fn with_attachment(mut self, attachment: Attachment) -> Self {
		self.attachments.push(attachment);
		self
	}

	/// Set all attachments
	pub fn with_attachments(mut self, attachments: Vec<Attachment>) -> Self {
		self.attachments = attachments;
		self
	}

	/// Sender and sent are ignored
	pub fn send<W: WriteExtraExt>(&self, w: &mut W, keypair: Option<&Keypair>) -> Result<()> {
		let mut bytes = Vec::new();

		match keypair {
			Some(keypair) => bytes.write_b8(keypair.public.as_bytes()),
			None => bytes.write_u8(0)
		}?;
		bytes.write_u64::<LE>(Utc::now().timestamp() as u64)?;
		bytes.write_str(&self.subject)?;

		bytes.write_str(&self.body_type)?;
		bytes.write_b32(&self.body)?;

		// TODO: check for >255
		bytes.write_u8(self.attachments.len() as u8)?;
		for file in &self.attachments {
			file.write(&mut bytes)?;
		}

		// send message
		w.write_b32(&bytes)?;

		// send signature
		if let Some(keypair) = keypair {
			let signature = keypair.sign(&bytes);
			println!("[DEBUG] signature sent = {:?}", signature.to_bytes());
			w.write_all(&signature.to_bytes())?;
			println!("test {:?}", keypair.verify(&bytes, &signature));
		}

		Ok(())
	}
}


code:
pub use std::io::{Error, ErrorKind, Result};

pub use byteorder::{LittleEndian as LE, ReadBytesExt, WriteBytesExt};

pub trait WriteExtraExt : WriteBytesExt {
	/// Writes a utf-8 string prepended by a byte with the length, in bytes, of the string
	fn write_str(&mut self, s: &str) -> Result<()>;
	/// Writes a Vec of bytes prepended with 1 byte length
	fn write_b8(&mut self, vec: &[u8]) -> Result<()>;
	/// Writes a Vec of bytes prepended with 4 bytes length
	fn write_b32(&mut self, vec: &[u8]) -> Result<()>;
}

impl <W: WriteBytesExt> WriteExtraExt for W {
	fn write_str(&mut self, s: &str) -> Result<()> {
		// forbid writing strings that are too long to read
		if s.len() > u8::MAX.into() {
			return Err(Error::new(ErrorKind::InvalidInput, "String too long to read back"));
		}

		self.write_u8(s.len() as u8)?;
		self.write_all(s.as_bytes())
	}

	fn write_b8(&mut self, vec: &[u8]) -> Result<()> {
		if vec.len() > u8::MAX.into() {
			return Err(Error::new(ErrorKind::InvalidInput, "Data too long to read back"));
		}

		self.write_u8(vec.len() as u8)?;
		self.write_all(&vec)
	}

	fn write_b32(&mut self, vec: &[u8]) -> Result<()> {
		if vec.len() > u32::MAX as usize {
			return Err(Error::new(ErrorKind::InvalidInput, "Data too long to read back"));
		}

		self.write_u32::<LE>(vec.len() as u32)?;
		self.write_all(&vec)
	}
}

pub trait ReadExtraExt : ReadBytesExt {
	/// Reads a 0-255 byte utf-8 encoded string
	fn read_str(&mut self) -> Result<String>;
	/// Reads a Vec of bytes prepended with 1 byte length
	fn read_b8(&mut self) -> Result<Vec<u8>>;
	/// Reads a Vec of bytes prepended with 4 bytes length
	fn read_b32(&mut self, limit: u32) -> Result<Vec<u8>>;
}

impl <R: ReadBytesExt> ReadExtraExt for R {
	fn read_str(&mut self) -> Result<String> {
		let bytes = self.read_b8()?;
		String::from_utf8(bytes)
			.map_err(|_| Error::new(ErrorKind::InvalidData, "String contains non-utf8 bytes"))
	}

	fn read_b8(&mut self) -> Result<Vec<u8>> {
		let len = self.read_u8()? as usize;
		let mut bytes = vec![0; len];
		self.read_exact(&mut bytes)?;
		Ok(bytes)
	}

	fn read_b32(&mut self, limit: u32) -> Result<Vec<u8>> {
		let len = self.read_u32::<LE>()?;
		if len > limit {
			return Err(Error::new(ErrorKind::InvalidData, "Data exceeds limit"));
		}

		let mut bytes = vec![0; len as usize];
		self.read_exact(&mut bytes)?;
		Ok(bytes)
	}
}


code:
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto

###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs     diff=csharp

###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln       merge=binary
#*.csproj    merge=binary
#*.vbproj    merge=binary
#*.vcxproj   merge=binary
#*.vcproj    merge=binary
#*.dbproj    merge=binary
#*.fsproj    merge=binary
#*.lsproj    merge=binary
#*.wixproj   merge=binary
#*.modelproj merge=binary
#*.sqlproj   merge=binary
#*.wwaproj   merge=binary

###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg   binary
#*.png   binary
#*.gif   binary

###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc   diff=astextplain
#*.DOC   diff=astextplain
#*.docx  diff=astextplain
#*.DOCX  diff=astextplain
#*.dot   diff=astextplain
#*.DOT   diff=astextplain
#*.pdf   diff=astextplain
#*.PDF   diff=astextplain
#*.rtf   diff=astextplain
#*.RTF   diff=astextplain

repo_name: CaIcYo/rimworld

path: .gitattributes


code:
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/

# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# Visual Studio 2017 auto generated files
Generated\ Files/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUNIT
*.VisualState.xml
TestResult.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# Visual Studio Trace Files
*.e2e

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# JustCode is a .NET coding add-in
.JustCode

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# Visual Studio code coverage results
*.coverage
*.coveragexml

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs

# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak

# SQL Server files
*.mdf
*.ldf
*.ndf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- Backup*.rdl

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# JetBrains Rider
.idea/
*.sln.iml

# CodeRush personal settings
.cr/personal

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio
*.tss

# Telerik's JustMock configuration file
*.jmconfig

# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

# OpenCover UI analysis results
OpenCover/

# Azure Stream Analytics local run output
ASALocalRun/

# MSBuild Binary and Structured Log
*.binlog

# NVidia Nsight GPU debugger configuration file
*.nvuser

# MFractors (Xamarin productivity tool) working folder
.mfractor/

# Local History for Visual Studio
.localhistory/

# BeatPulse healthcheck temp database
healthchecksdb
/Source/Patches/PawnAnimationPatches/HarmonyPatch_Pawn_DrawTracker.cs
/Source/Patches/PawnAnimationPatches/HarmonyPatch_PawnRotation.cs
/Source/Patches/PawnAnimationPatches/HarmonyPatch_PawnRenderer.cs
/Source/Patches/OtherModPatches/HarmonyPatch_ShowHairWithHats.cs
/Source/Patches/OtherModPatches/HarmonyPatch_FacialAnimation.cs
/Source/Patches/OtherModPatches/HarmonyPatch_DontShaveYourHead.cs
/Source/Patches/OtherModPatches/HarmonyPatch_CSL.cs
/Source/Patches/OtherModPatches/HarmonyPatch_AlienRace.cs
/Source/Patches/ThingAnimationPatches/HarmonyPatch_ThingDrawAt.cs
/Defs/AnimationDefs/Animations_SexToys.xml


code:
<?xml version="1.0" encoding="utf-8"?>

<ModMetaData>
	<name>Rimworld-Animations</name>
	<author>C0ffee</author>
  <url>https://gitgud.io/c0ffeeeeeeee/rimworld-animations</url>
	<supportedVersions>

1.1

1.2

	</supportedVersions>
	<packageId>c0ffee.rimworld.animations</packageId>
	<modDependencies>

			<packageId>brrainz.harmony</packageId>
			<displayName>Harmony</displayName>
			<steamWorkshopUrl>steam://url/CommunityFilePage/2009463077</steamWorkshopUrl>
			<downloadUrl>https://github.com/pardeike/HarmonyRimWorld/releases/latest</downloadUrl>

			<packageId>UnlimitedHugs.HugsLib</packageId>
			<displayName>HugsLib</displayName>
			<downloadUrl>https://github.com/UnlimitedHugs/RimworldHugsLib/releases/latest</downloadUrl>
			<steamWorkshopUrl>steam://url/CommunityFilePage/818773962</steamWorkshopUrl>

      <packageId>rim.job.world</packageId>
      <displayName>RimJobWorld</displayName>
      <downloadUrl>https://www.loverslab.com/topic/110270-mod-rimjobworld/</downloadUrl>

	</modDependencies>
	<loadAfter>

UnlimitedHugs.HugsLib

brrainz.harmony

rim.job.world

	</loadAfter>
	<description>
    Rimworld Animations! Hurray!

    Questions or bugs?
    Chat with me on the forums: https://www.loverslab.com/topic/140386-rjw-animations/
    Or on the rjw discord: https://discord.gg/CXwHhv8

  </description>
</ModMetaData>


code:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Manifest>
  <identifier>Rimworld-Animations</identifier>
  <version>1.1.2</version>
</Manifest>