forked from lug/matterbridge
		
	Compare commits
	
		
			188 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 1665c93d3b | ||
|   | b51fdbce9f | ||
|   | 351b423e15 | ||
|   | 7690be1647 | ||
|   | 68aeb93afa | ||
|   | 51062863a5 | ||
|   | 4fb4b7aa6c | ||
|   | 7f3cbcedc0 | ||
|   | 6ef09def81 | ||
|   | c4c6aff9a5 | ||
|   | d71850cef6 | ||
|   | 2597c9bfac | ||
|   | 93307b57aa | ||
|   | 618953c865 | ||
|   | e04dd78624 | ||
|   | fa0c4025f7 | ||
|   | 2d2d185200 | ||
|   | cb7278eb50 | ||
|   | 89aa114192 | ||
|   | ed062e0ce5 | ||
|   | a69ef8402b | ||
|   | 8779f67d2d | ||
|   | e4b72136b8 | ||
|   | 4ff5091bc2 | ||
|   | 6f131250f1 | ||
|   | 221a63d980 | ||
|   | d02eda147c | ||
|   | 9b25716136 | ||
|   | 6628a47f23 | ||
|   | ec0e6bc3f8 | ||
|   | d2c02be3a0 | ||
|   | 594492fbdd | ||
|   | bd9ea7a88d | ||
|   | 51327a4056 | ||
|   | 33bd60528b | ||
|   | 7e54474111 | ||
|   | e307069d62 | ||
|   | 91db63294c | ||
|   | fd04e08c9c | ||
|   | 6576409d60 | ||
|   | 045cb2058c | ||
|   | d03afc12fd | ||
|   | 48799a3cff | ||
|   | dba259e9f1 | ||
|   | 07885f5810 | ||
|   | 696c518550 | ||
|   | 411ef2691c | ||
|   | fc6074ea9f | ||
|   | ab1670e2ce | ||
|   | 9142a33bbf | ||
|   | f6eefa4ecc | ||
|   | f1db166ac4 | ||
|   | 887c2bc56d | ||
|   | f0738a93c3 | ||
|   | 75381c2c6e | ||
|   | bf0b9959d1 | ||
|   | 406a54b597 | ||
|   | be04d1a862 | ||
|   | 85b2d5a124 | ||
|   | 521a7ed7b0 | ||
|   | 529b188164 | ||
|   | 8d307d8134 | ||
|   | 8c675b52bc | ||
|   | aa51aa2aa0 | ||
|   | 86865c6da5 | ||
|   | 45296100df | ||
|   | 1605fbc012 | ||
|   | c6c92e273d | ||
|   | 467b373c43 | ||
|   | 72ce7f06e9 | ||
|   | 346a7284f7 | ||
|   | ee4ac67081 | ||
|   | 5a93d14d75 | ||
|   | 96a47a60ad | ||
|   | b24a47ad7f | ||
|   | cd1fd1bb7c | ||
|   | d44df7b6e6 | ||
|   | 9d1ac0c84b | ||
|   | 76af9cba5a | ||
|   | b69fc30902 | ||
|   | c3174f4de9 | ||
|   | 99ce68e9ba | ||
|   | 0cf73673a9 | ||
|   | 08f442dc7b | ||
|   | 8a8b95228c | ||
|   | 31a752fa21 | ||
|   | a83831e68d | ||
|   | a12a8d4fe2 | ||
|   | e57f3a7e6c | ||
|   | 68fbed9281 | ||
|   | 8bfaa007d5 | ||
|   | 76360f89c1 | ||
|   | d525230abd | ||
|   | b4aa637d41 | ||
|   | 7c4334d0de | ||
|   | 062be8d7c9 | ||
|   | db25ee59c5 | ||
|   | 4b0bc6d0bf | ||
|   | 8c0b04b995 | ||
|   | e5989adf92 | ||
|   | 9e5da2f9d7 | ||
|   | a284a228a3 | ||
|   | 2133e0d1be | ||
|   | a6f37f1d61 | ||
|   | 9de9151826 | ||
|   | fdd5ada98c | ||
|   | 80fcf18e24 | ||
|   | ab94b5ca7a | ||
|   | 8d2ce56c37 | ||
|   | 1ec324354b | ||
|   | 16be6601c8 | ||
|   | 98027446c8 | ||
|   | f2f1d874e1 | ||
|   | 25a72113b1 | ||
|   | 79c4ad5015 | ||
|   | e24f1c7c87 | ||
|   | dbf8a326d5 | ||
|   | 0bc9c70c66 | ||
|   | 594d2155e3 | ||
|   | 20dbd71306 | ||
|   | 6a727b9723 | ||
|   | 02a5bc096f | ||
|   | 2110db6f0c | ||
|   | 2bac867382 | ||
|   | 5fbd8a3be0 | ||
|   | ad6440b603 | ||
|   | 064b6a915f | ||
|   | 1578ebb0e2 | ||
|   | 73525a4bbc | ||
|   | d62f49d1fc | ||
|   | 63b88e77f2 | ||
|   | 3d8f15c20b | ||
|   | cac5d56d60 | ||
|   | bd2a672c14 | ||
|   | 82396e73f5 | ||
|   | ba928b169d | ||
|   | 4fed720f97 | ||
|   | 78238c85d4 | ||
|   | 4f2ae7b73f | ||
|   | f82a9cc7ac | ||
|   | cce7624ab8 | ||
|   | c5ecd09172 | ||
|   | 7b21c1c2f4 | ||
|   | f8714d81f5 | ||
|   | 8622656005 | ||
|   | 52237fadb6 | ||
|   | 222cccf388 | ||
|   | bab308508e | ||
|   | dedb83c867 | ||
|   | 723a90cdd6 | ||
|   | 67d2398fa8 | ||
|   | 5f3b6ec007 | ||
|   | 55ab0c12f1 | ||
|   | d1227b5fc9 | ||
|   | 6ea368c383 | ||
|   | e92b6de09f | ||
|   | e622587db4 | ||
|   | f2efc06d1f | ||
|   | a2b94452db | ||
|   | 4c506f7cc3 | ||
|   | 7886f05e88 | ||
|   | f58be0d1c1 | ||
|   | 1152394bc1 | ||
|   | a082b5a590 | ||
|   | bae9484df2 | ||
|   | 6f78485878 | ||
|   | fd0fe3390b | ||
|   | 2522158127 | ||
|   | 8be107cecc | ||
|   | 5aab158c0b | ||
|   | 1d33e60e36 | ||
|   | 83c28cb857 | ||
|   | df5bce27b0 | ||
|   | 2b15739b48 | ||
|   | 3480c88e90 | ||
|   | 432cd0f99d | ||
|   | e8b3e9b22d | ||
|   | d4a47671ea | ||
|   | 0bcd1e62f3 | ||
|   | 80822b7fff | ||
|   | 78f1011f52 | ||
|   | 67f6257617 | ||
|   | 169c614489 | ||
|   | da908c438a | ||
|   | 9c9c4bf1f9 | ||
|   | 7764493298 | ||
|   | 64a20ee61b | ||
|   | 62d1af8c37 | 
							
								
								
									
										28
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							| @@ -1,22 +1,36 @@ | ||||
| If you have a configuration problem, please first try to create a basic configuration following the instructions on [the wiki](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) before filing an issue. | ||||
| <!-- This is a bug report template. By following the instructions below and | ||||
| filling out the sections with your information, you will help the us to get all | ||||
| the necessary data to fix your issue. | ||||
|  | ||||
| Please answer the following questions.  | ||||
| You can also preview your report before submitting it. | ||||
|  | ||||
| ### Which version of matterbridge are you using? | ||||
| run ```matterbridge -version``` | ||||
| Text between <!-- and --> marks will be invisible in the report. | ||||
| --> | ||||
|  | ||||
| ### If you're having problems with mattermost please specify mattermost version.  | ||||
| <!-- If you have a configuration problem, please first try to create a basic configuration following the instructions on [the wiki](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) before filing an issue. --> | ||||
|  | ||||
|  | ||||
| ### Environment | ||||
| <!-- run `matterbridge -version` --> | ||||
| <!-- If you're having problems with mattermost also specify the mattermost version. --> | ||||
| Version: | ||||
|  | ||||
| <!-- What operating system are you using ? (be as specific as possible) --> | ||||
| Operating system: | ||||
|  | ||||
| <!-- If you compiled matterbridge yourself: | ||||
|        * Specify the output of `go version`  | ||||
|        * Specify the output of `git rev-parse HEAD` --> | ||||
|  | ||||
| ### Please describe the expected behavior. | ||||
|  | ||||
|  | ||||
| ### Please describe the actual behavior.  | ||||
| #### Use logs from running ```matterbridge -debug``` if possible. | ||||
| <!-- Use logs from running `matterbridge -debug` if possible. --> | ||||
|  | ||||
|  | ||||
| ### Any steps to reproduce the behavior? | ||||
|  | ||||
|  | ||||
| ### Please add your configuration file  | ||||
| #### (be sure to exclude or anonymize private data (tokens/passwords)) | ||||
| <!-- (be sure to exclude or anonymize private data (tokens/passwords)) --> | ||||
|   | ||||
							
								
								
									
										26
									
								
								.github/ISSUE_TEMPLATE/Bug_report.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								.github/ISSUE_TEMPLATE/Bug_report.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| --- | ||||
| name: Bug report | ||||
| about: Create a report to help us improve. (Check the FAQ on the wiki first) | ||||
|  | ||||
| --- | ||||
|  | ||||
| **Describe the bug** | ||||
| A clear and concise description of what the bug is. | ||||
|  | ||||
| **To Reproduce** | ||||
| Steps to reproduce the behavior: | ||||
|  | ||||
| **Expected behavior** | ||||
| A clear and concise description of what you expected to happen. | ||||
|  | ||||
| **Screenshots/debug logs** | ||||
| If applicable, add screenshots to help explain your problem. | ||||
| Use logs from running `matterbridge -debug` if possible. | ||||
|  | ||||
| **Environment (please complete the following information):** | ||||
|  - OS: [e.g. linux] | ||||
|  - Matterbridge version: output of  `matterbridge -version` | ||||
|  - If self compiled: output of `git rev-parse HEAD` | ||||
|  | ||||
| **Additional context** | ||||
| Please add your configuration file  (be sure to exclude or anonymize private data (tokens/passwords)) | ||||
							
								
								
									
										17
									
								
								.github/ISSUE_TEMPLATE/Feature_request.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								.github/ISSUE_TEMPLATE/Feature_request.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| --- | ||||
| name: Feature request | ||||
| about: Suggest an idea for this project | ||||
|  | ||||
| --- | ||||
|  | ||||
| **Is your feature request related to a problem? Please describe.** | ||||
| A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] | ||||
|  | ||||
| **Describe the solution you'd like** | ||||
| A clear and concise description of what you want to happen. | ||||
|  | ||||
| **Describe alternatives you've considered** | ||||
| A clear and concise description of any alternative solutions or features you've considered. | ||||
|  | ||||
| **Additional context** | ||||
| Add any other context or screenshots about the feature request here. | ||||
| @@ -1,7 +1,7 @@ | ||||
| language: go | ||||
| go: | ||||
|     #- 1.7.x | ||||
|     - 1.9.x | ||||
|     - 1.10.x | ||||
|       # - tip | ||||
|  | ||||
| # we have everything vendored | ||||
| @@ -34,15 +34,17 @@ before_script: | ||||
| # flunk the build and immediately stop. It's sorta like having | ||||
| # set -e enabled in bash.  | ||||
| script: | ||||
|   - test -z $(gofmt -s -l $GO_FILES)  # Fail if a .go file hasn't been formatted with gofmt | ||||
|  #- test -z $(gofmt -s -l $GO_FILES)  # Fail if a .go file hasn't been formatted with gofmt | ||||
|   - go test -v -race $PKGS            # Run all the tests with the race detector enabled | ||||
|   - go vet $PKGS                      # go vet is the official Go static analyzer | ||||
|  #  - go vet $PKGS                      # go vet is the official Go static analyzer | ||||
|   - megacheck $PKGS                   # "go vet on steroids" + linter | ||||
|   - /bin/bash ci/bintray.sh | ||||
|   #- golint -set_exit_status $PKGS     # one last linter | ||||
|  | ||||
| deploy: | ||||
|   provider: bintray | ||||
|   edge: | ||||
|     branch: v1.8.47 | ||||
|   file: ci/deploy.json | ||||
|   user: 42wim | ||||
|   key: | ||||
|   | ||||
							
								
								
									
										41
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,18 +1,21 @@ | ||||
| # matterbridge | ||||
| Click on one of the badges below to join the chat    | ||||
|  | ||||
| [](https://gitter.im/42wim/matterbridge) [](https://webchat.freenode.net/?channels=matterbridgechat) [](https://discord.gg/AkKPtrQ) [](https://riot.im/app/#/room/#matterbridge:matrix.org) [](https://join.slack.com/matterbridgechat/shared_invite/MjEwODMxNjU1NDMwLTE0OTk2MTU3NTMtMzZkZmRiNDZhOA) [](https://framateam.org/signup_user_complete/?id=tfqm33ggop8x3qgu4boeieta6e) [](https://inverse.chat) [](https://www.twitch.tv/matterbridge) | ||||
| [](https://gitter.im/42wim/matterbridge) [](https://webchat.freenode.net/?channels=matterbridgechat) [](https://discord.gg/AkKPtrQ) [](https://riot.im/app/#/room/#matterbridge:matrix.org) [](https://join.slack.com/matterbridgechat/shared_invite/MjEwODMxNjU1NDMwLTE0OTk2MTU3NTMtMzZkZmRiNDZhOA) [](https://framateam.org/signup_user_complete/?id=tfqm33ggop8x3qgu4boeieta6e) [](https://inverse.chat) [](https://www.twitch.tv/matterbridge) [](https://matterbridge.zulipchat.com/register/) | ||||
|  | ||||
| [](https://github.com/42wim/matterbridge/releases/latest) [](https://bintray.com/42wim/nightly/Matterbridge/_latestVersion) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| Simple bridge between Mattermost, IRC, XMPP, Gitter, Slack, Discord, Telegram, Rocket.Chat, Hipchat(via xmpp), Matrix and Steam. | ||||
| Has a REST API.   | ||||
| Simple bridge between IRC, XMPP, Gitter, Mattermost, Slack, Discord, Telegram, Rocket.Chat, Hipchat(via xmpp), Matrix, Steam, ssh-chat and Zulip | ||||
| Has a REST API.    | ||||
| Minecraft server chat support via [MatterLink](https://github.com/elytra/MatterLink) | ||||
|  | ||||
| **Mattermost isn't required to run matterbridge. It bridges between any supported protocol.**    | ||||
| (The name matterbridge is a remnant when it was only bridging mattermost) | ||||
|  | ||||
| # Table of Contents | ||||
|  * [Features](#features) | ||||
|  * [Features](https://github.com/42wim/matterbridge/wiki/Features) | ||||
|  * [Requirements](#requirements) | ||||
|  * [Screenshots](https://github.com/42wim/matterbridge/wiki/) | ||||
|  * [Installing](#installing) | ||||
| @@ -28,13 +31,13 @@ Minecraft server chat support via [MatterLink](https://github.com/elytra/MatterL | ||||
|  * [Thanks](#thanks) | ||||
|  | ||||
| # Features | ||||
| * Relays public channel messages between multiple mattermost, IRC, XMPP, Gitter, Slack, Discord, Telegram, Rocket.Chat, Hipchat (via xmpp), Matrix and Steam.  | ||||
|   Pick and mix. | ||||
| * Support private groups on your mattermost/slack. | ||||
| * Allow for bridging the same bridges, which means you can eg bridge between multiple mattermosts. | ||||
| * The bridge is now a gateway which has support multiple in and out bridges. (and supports multiple gateways). | ||||
| * Edits and delete messages across bridges that support it (mattermost,slack,discord,gitter,telegram) | ||||
| * REST API to read/post messages to bridges (WIP). | ||||
| * [Support bridging between any protocols](https://github.com/42wim/matterbridge/wiki/Features#support-bridging-between-any-protocols) | ||||
| * [Support multiple gateways(bridges) for your protocols](https://github.com/42wim/matterbridge/wiki/Features#support-multiple-gatewaysbridges-for-your-protocols) | ||||
| * [Message edits and deletes](https://github.com/42wim/matterbridge/wiki/Features#message-edits-and-deletes) | ||||
| * [Attachment / files handling](https://github.com/42wim/matterbridge/wiki/Features#attachment--files-handling) | ||||
| * [Username and avatar spoofing](https://github.com/42wim/matterbridge/wiki/Features#username-and-avatar-spoofing) | ||||
| * [Private groups](https://github.com/42wim/matterbridge/wiki/Features#private-groups) | ||||
| * [API](https://github.com/42wim/matterbridge/wiki/Features#api) | ||||
|  | ||||
| ## API | ||||
| The API is very basic at the moment and rather undocumented. | ||||
| @@ -46,7 +49,7 @@ Used by at least 2 projects. Feel free to make a PR to add your project to this | ||||
|  | ||||
| # Requirements | ||||
| Accounts to one of the supported bridges | ||||
| * [Mattermost](https://github.com/mattermost/platform/) 3.8.x - 3.10.x, 4.x | ||||
| * [Mattermost](https://github.com/mattermost/platform/) 3.8.x - 3.10.x, 4.x, 5.x | ||||
| * [IRC](http://www.mirc.com/servers.html) | ||||
| * [XMPP](https://jabber.org) | ||||
| * [Gitter](https://gitter.im) | ||||
| @@ -58,17 +61,21 @@ Accounts to one of the supported bridges | ||||
| * [Matrix](https://matrix.org) | ||||
| * [Steam](https://store.steampowered.com/) | ||||
| * [Twitch](https://twitch.tv) | ||||
| * [Ssh-chat](https://github.com/shazow/ssh-chat) | ||||
| * [Zulip](https://zulipchat.com) | ||||
|  | ||||
| # Screenshots | ||||
| See https://github.com/42wim/matterbridge/wiki | ||||
|  | ||||
| # Installing | ||||
| ## Binaries | ||||
| * Latest stable release [v1.7.1](https://github.com/42wim/matterbridge/releases/latest) | ||||
| * Latest stable release [v1.11.2](https://github.com/42wim/matterbridge/releases/latest) | ||||
| * Development releases (follows master) can be downloaded [here](https://dl.bintray.com/42wim/nightly/)   | ||||
|  | ||||
| ## Building | ||||
| Go 1.8+ is required. Make sure you have [Go](https://golang.org/doc/install) properly installed, including setting up your [GOPATH] (https://golang.org/doc/code.html#GOPATH) | ||||
| Go 1.8+ is required. Make sure you have [Go](https://golang.org/doc/install) properly installed, including setting up your [GOPATH](https://golang.org/doc/code.html#GOPATH). | ||||
|  | ||||
| After Go is setup, download matterbridge to your $GOPATH directory.  | ||||
|  | ||||
| ``` | ||||
| cd $GOPATH | ||||
| @@ -180,11 +187,14 @@ Want to tip ? | ||||
| * btc: 1N7cKHj5SfqBHBzDJ6kad4BzeqUBBS2zhs | ||||
|  | ||||
| # Thanks | ||||
| [](https://www.digitalocean.com/) for sponsoring demo/testing droplets. | ||||
|  | ||||
| Matterbridge wouldn't exist without these libraries: | ||||
| * discord - https://github.com/bwmarrin/discordgo | ||||
| * echo - https://github.com/labstack/echo | ||||
| * gitter - https://github.com/sromku/go-gitter | ||||
| * gops - https://github.com/google/gops | ||||
| * gozulipbot - https://github.com/ifo/gozulipbot | ||||
| * irc - https://github.com/lrstanley/girc | ||||
| * mattermost - https://github.com/mattermost/platform | ||||
| * matrix - https://github.com/matrix-org/gomatrix | ||||
| @@ -192,3 +202,4 @@ Matterbridge wouldn't exist without these libraries: | ||||
| * steam - https://github.com/Philipp15b/go-steam | ||||
| * telegram - https://github.com/go-telegram-bot-api/telegram-bot-api | ||||
| * xmpp - https://github.com/mattn/go-xmpp | ||||
| * zulip - https://github.com/ifo/gozulipbot | ||||
|   | ||||
| @@ -2,20 +2,21 @@ package api | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	"github.com/labstack/echo" | ||||
| 	"github.com/labstack/echo/middleware" | ||||
| 	"github.com/zfjagann/golang-ring" | ||||
| 	"net/http" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/labstack/echo" | ||||
| 	"github.com/labstack/echo/middleware" | ||||
| 	"github.com/zfjagann/golang-ring" | ||||
| ) | ||||
|  | ||||
| type Api struct { | ||||
| 	Messages ring.Ring | ||||
| 	sync.RWMutex | ||||
| 	*config.BridgeConfig | ||||
| 	*bridge.Config | ||||
| } | ||||
|  | ||||
| type ApiMessage struct { | ||||
| @@ -26,28 +27,27 @@ type ApiMessage struct { | ||||
| 	Gateway  string `json:"gateway"` | ||||
| } | ||||
|  | ||||
| var flog *log.Entry | ||||
| var protocol = "api" | ||||
|  | ||||
| func init() { | ||||
| 	flog = log.WithFields(log.Fields{"module": protocol}) | ||||
| } | ||||
|  | ||||
| func New(cfg *config.BridgeConfig) *Api { | ||||
| 	b := &Api{BridgeConfig: cfg} | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	b := &Api{Config: cfg} | ||||
| 	e := echo.New() | ||||
| 	e.HideBanner = true | ||||
| 	e.HidePort = true | ||||
| 	b.Messages = ring.Ring{} | ||||
| 	b.Messages.SetCapacity(b.Config.Buffer) | ||||
| 	if b.Config.Token != "" { | ||||
| 	b.Messages.SetCapacity(b.GetInt("Buffer")) | ||||
| 	if b.GetString("Token") != "" { | ||||
| 		e.Use(middleware.KeyAuth(func(key string, c echo.Context) (bool, error) { | ||||
| 			return key == b.Config.Token, nil | ||||
| 			return key == b.GetString("Token"), nil | ||||
| 		})) | ||||
| 	} | ||||
| 	e.GET("/api/messages", b.handleMessages) | ||||
| 	e.GET("/api/stream", b.handleStream) | ||||
| 	e.POST("/api/message", b.handlePostMessage) | ||||
| 	go func() { | ||||
| 		flog.Fatal(e.Start(b.Config.BindAddress)) | ||||
| 		if b.GetString("BindAddress") == "" { | ||||
| 			b.Log.Fatalf("No BindAddress configured.") | ||||
| 		} | ||||
| 		b.Log.Infof("Listening on %s", b.GetString("BindAddress")) | ||||
| 		b.Log.Fatal(e.Start(b.GetString("BindAddress"))) | ||||
| 	}() | ||||
| 	return b | ||||
| } | ||||
| @@ -76,21 +76,18 @@ func (b *Api) Send(msg config.Message) (string, error) { | ||||
| } | ||||
|  | ||||
| func (b *Api) handlePostMessage(c echo.Context) error { | ||||
| 	message := &ApiMessage{} | ||||
| 	if err := c.Bind(message); err != nil { | ||||
| 	message := config.Message{} | ||||
| 	if err := c.Bind(&message); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	flog.Debugf("Sending message from %s on %s to gateway", message.Username, "api") | ||||
| 	b.Remote <- config.Message{ | ||||
| 		Text:     message.Text, | ||||
| 		Username: message.Username, | ||||
| 		UserID:   message.UserID, | ||||
| 		Channel:  "api", | ||||
| 		Avatar:   message.Avatar, | ||||
| 		Account:  b.Account, | ||||
| 		Gateway:  message.Gateway, | ||||
| 		Protocol: "api", | ||||
| 	} | ||||
| 	// these values are fixed | ||||
| 	message.Channel = "api" | ||||
| 	message.Protocol = "api" | ||||
| 	message.Account = b.Account | ||||
| 	message.ID = "" | ||||
| 	message.Timestamp = time.Now() | ||||
| 	b.Log.Debugf("Sending message from %s on %s to gateway", message.Username, "api") | ||||
| 	b.Remote <- message | ||||
| 	return c.JSON(http.StatusOK, message) | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										110
									
								
								bridge/bridge.go
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								bridge/bridge.go
									
									
									
									
									
								
							| @@ -1,20 +1,8 @@ | ||||
| package bridge | ||||
|  | ||||
| import ( | ||||
| 	"github.com/42wim/matterbridge/bridge/api" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/discord" | ||||
| 	"github.com/42wim/matterbridge/bridge/gitter" | ||||
| 	"github.com/42wim/matterbridge/bridge/irc" | ||||
| 	"github.com/42wim/matterbridge/bridge/matrix" | ||||
| 	"github.com/42wim/matterbridge/bridge/mattermost" | ||||
| 	"github.com/42wim/matterbridge/bridge/rocketchat" | ||||
| 	"github.com/42wim/matterbridge/bridge/slack" | ||||
| 	"github.com/42wim/matterbridge/bridge/sshchat" | ||||
| 	"github.com/42wim/matterbridge/bridge/steam" | ||||
| 	"github.com/42wim/matterbridge/bridge/telegram" | ||||
| 	"github.com/42wim/matterbridge/bridge/xmpp" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	log "github.com/sirupsen/logrus" | ||||
|  | ||||
| 	"strings" | ||||
| ) | ||||
| @@ -27,16 +15,28 @@ type Bridger interface { | ||||
| } | ||||
|  | ||||
| type Bridge struct { | ||||
| 	Config config.Protocol | ||||
| 	Bridger | ||||
| 	Name     string | ||||
| 	Account  string | ||||
| 	Protocol string | ||||
| 	Channels map[string]config.ChannelInfo | ||||
| 	Joined   map[string]bool | ||||
| 	Log      *log.Entry | ||||
| 	Config   *config.Config | ||||
| 	General  *config.Protocol | ||||
| } | ||||
|  | ||||
| func New(cfg *config.Config, bridge *config.Bridge, c chan config.Message) *Bridge { | ||||
| type Config struct { | ||||
| 	//	General *config.Protocol | ||||
| 	Remote chan config.Message | ||||
| 	Log    *log.Entry | ||||
| 	*Bridge | ||||
| } | ||||
|  | ||||
| // Factory is the factory function to create a bridge | ||||
| type Factory func(*Config) Bridger | ||||
|  | ||||
| func New(bridge *config.Bridge) *Bridge { | ||||
| 	b := new(Bridge) | ||||
| 	b.Channels = make(map[string]config.ChannelInfo) | ||||
| 	accInfo := strings.Split(bridge.Account, ".") | ||||
| @@ -46,49 +46,6 @@ func New(cfg *config.Config, bridge *config.Bridge, c chan config.Message) *Brid | ||||
| 	b.Protocol = protocol | ||||
| 	b.Account = bridge.Account | ||||
| 	b.Joined = make(map[string]bool) | ||||
| 	bridgeConfig := &config.BridgeConfig{General: &cfg.General, Account: bridge.Account, Remote: c} | ||||
|  | ||||
| 	// override config from environment | ||||
| 	config.OverrideCfgFromEnv(cfg, protocol, name) | ||||
| 	switch protocol { | ||||
| 	case "mattermost": | ||||
| 		bridgeConfig.Config = cfg.Mattermost[name] | ||||
| 		b.Bridger = bmattermost.New(bridgeConfig) | ||||
| 	case "irc": | ||||
| 		bridgeConfig.Config = cfg.IRC[name] | ||||
| 		b.Bridger = birc.New(bridgeConfig) | ||||
| 	case "gitter": | ||||
| 		bridgeConfig.Config = cfg.Gitter[name] | ||||
| 		b.Bridger = bgitter.New(bridgeConfig) | ||||
| 	case "slack": | ||||
| 		bridgeConfig.Config = cfg.Slack[name] | ||||
| 		b.Bridger = bslack.New(bridgeConfig) | ||||
| 	case "xmpp": | ||||
| 		bridgeConfig.Config = cfg.Xmpp[name] | ||||
| 		b.Bridger = bxmpp.New(bridgeConfig) | ||||
| 	case "discord": | ||||
| 		bridgeConfig.Config = cfg.Discord[name] | ||||
| 		b.Bridger = bdiscord.New(bridgeConfig) | ||||
| 	case "telegram": | ||||
| 		bridgeConfig.Config = cfg.Telegram[name] | ||||
| 		b.Bridger = btelegram.New(bridgeConfig) | ||||
| 	case "rocketchat": | ||||
| 		bridgeConfig.Config = cfg.Rocketchat[name] | ||||
| 		b.Bridger = brocketchat.New(bridgeConfig) | ||||
| 	case "matrix": | ||||
| 		bridgeConfig.Config = cfg.Matrix[name] | ||||
| 		b.Bridger = bmatrix.New(bridgeConfig) | ||||
| 	case "steam": | ||||
| 		bridgeConfig.Config = cfg.Steam[name] | ||||
| 		b.Bridger = bsteam.New(bridgeConfig) | ||||
| 	case "sshchat": | ||||
| 		bridgeConfig.Config = cfg.Sshchat[name] | ||||
| 		b.Bridger = bsshchat.New(bridgeConfig) | ||||
| 	case "api": | ||||
| 		bridgeConfig.Config = cfg.Api[name] | ||||
| 		b.Bridger = api.New(bridgeConfig) | ||||
| 	} | ||||
| 	b.Config = bridgeConfig.Config | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| @@ -100,7 +57,7 @@ func (b *Bridge) JoinChannels() error { | ||||
| func (b *Bridge) joinChannels(channels map[string]config.ChannelInfo, exists map[string]bool) error { | ||||
| 	for ID, channel := range channels { | ||||
| 		if !exists[ID] { | ||||
| 			log.Infof("%s: joining %s (%s)", b.Account, channel.Name, ID) | ||||
| 			b.Log.Infof("%s: joining %s (ID: %s)", b.Account, channel.Name, ID) | ||||
| 			err := b.JoinChannel(channel) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| @@ -110,3 +67,38 @@ func (b *Bridge) joinChannels(channels map[string]config.ChannelInfo, exists map | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Bridge) GetBool(key string) bool { | ||||
| 	if b.Config.GetBool(b.Account + "." + key) { | ||||
| 		return b.Config.GetBool(b.Account + "." + key) | ||||
| 	} | ||||
| 	return b.Config.GetBool("general." + key) | ||||
| } | ||||
|  | ||||
| func (b *Bridge) GetInt(key string) int { | ||||
| 	if b.Config.GetInt(b.Account+"."+key) != 0 { | ||||
| 		return b.Config.GetInt(b.Account + "." + key) | ||||
| 	} | ||||
| 	return b.Config.GetInt("general." + key) | ||||
| } | ||||
|  | ||||
| func (b *Bridge) GetString(key string) string { | ||||
| 	if b.Config.GetString(b.Account+"."+key) != "" { | ||||
| 		return b.Config.GetString(b.Account + "." + key) | ||||
| 	} | ||||
| 	return b.Config.GetString("general." + key) | ||||
| } | ||||
|  | ||||
| func (b *Bridge) GetStringSlice(key string) []string { | ||||
| 	if len(b.Config.GetStringSlice(b.Account+"."+key)) != 0 { | ||||
| 		return b.Config.GetStringSlice(b.Account + "." + key) | ||||
| 	} | ||||
| 	return b.Config.GetStringSlice("general." + key) | ||||
| } | ||||
|  | ||||
| func (b *Bridge) GetStringSlice2D(key string) [][]string { | ||||
| 	if len(b.Config.GetStringSlice2D(b.Account+"."+key)) != 0 { | ||||
| 		return b.Config.GetStringSlice2D(b.Account + "." + key) | ||||
| 	} | ||||
| 	return b.Config.GetStringSlice2D("general." + key) | ||||
| } | ||||
|   | ||||
| @@ -1,20 +1,27 @@ | ||||
| package config | ||||
|  | ||||
| import ( | ||||
| 	"github.com/BurntSushi/toml" | ||||
| 	"log" | ||||
| 	"bytes" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/fsnotify/fsnotify" | ||||
| 	prefixed "github.com/matterbridge/logrus-prefixed-formatter" | ||||
| 	log "github.com/sirupsen/logrus" | ||||
| 	"github.com/spf13/viper" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	EVENT_JOIN_LEAVE      = "join_leave" | ||||
| 	EVENT_FAILURE         = "failure" | ||||
| 	EVENT_REJOIN_CHANNELS = "rejoin_channels" | ||||
| 	EVENT_USER_ACTION     = "user_action" | ||||
| 	EVENT_MSG_DELETE      = "msg_delete" | ||||
| 	EVENT_JOIN_LEAVE        = "join_leave" | ||||
| 	EVENT_TOPIC_CHANGE      = "topic_change" | ||||
| 	EVENT_FAILURE           = "failure" | ||||
| 	EVENT_FILE_FAILURE_SIZE = "file_failure_size" | ||||
| 	EVENT_AVATAR_DOWNLOAD   = "avatar_download" | ||||
| 	EVENT_REJOIN_CHANNELS   = "rejoin_channels" | ||||
| 	EVENT_USER_ACTION       = "user_action" | ||||
| 	EVENT_MSG_DELETE        = "msg_delete" | ||||
| ) | ||||
|  | ||||
| type Message struct { | ||||
| @@ -37,6 +44,9 @@ type FileInfo struct { | ||||
| 	Data    *[]byte | ||||
| 	Comment string | ||||
| 	URL     string | ||||
| 	Size    int64 | ||||
| 	Avatar  bool | ||||
| 	SHA     string | ||||
| } | ||||
|  | ||||
| type ChannelInfo struct { | ||||
| @@ -53,14 +63,19 @@ type Protocol struct { | ||||
| 	BindAddress            string // mattermost, slack // DEPRECATED | ||||
| 	Buffer                 int    // api | ||||
| 	Charset                string // irc | ||||
| 	ColorNicks             bool   // only irc for now | ||||
| 	Debug                  bool   // general | ||||
| 	DebugLevel             int    // only for irc now | ||||
| 	EditSuffix             string // mattermost, slack, discord, telegram, gitter | ||||
| 	EditDisable            bool   // mattermost, slack, discord, telegram, gitter | ||||
| 	IconURL                string // mattermost, slack | ||||
| 	IgnoreNicks            string // all protocols | ||||
| 	IgnoreMessages         string // all protocols | ||||
| 	Jid                    string // xmpp | ||||
| 	Label                  string // all protocols | ||||
| 	Login                  string // mattermost, matrix | ||||
| 	MediaDownloadBlackList []string | ||||
| 	MediaDownloadPath      string // Basically MediaServerUpload, but instead of uploading it, just write it to a file on the same server. | ||||
| 	MediaDownloadSize      int    // all protocols | ||||
| 	MediaServerDownload    string | ||||
| 	MediaServerUpload      string | ||||
| @@ -78,21 +93,26 @@ type Protocol struct { | ||||
| 	NickServPassword       string     // IRC | ||||
| 	NicksPerRow            int        // mattermost, slack | ||||
| 	NoHomeServerSuffix     bool       // matrix | ||||
| 	NoSendJoinPart         bool       // all protocols | ||||
| 	NoTLS                  bool       // mattermost | ||||
| 	Password               string     // IRC,mattermost,XMPP,matrix | ||||
| 	PrefixMessagesWithNick bool       // mattemost, slack | ||||
| 	Protocol               string     // all protocols | ||||
| 	QuoteDisable           bool       // telegram | ||||
| 	QuoteFormat            string     // telegram | ||||
| 	RejoinDelay            int        // IRC | ||||
| 	ReplaceMessages        [][]string // all protocols | ||||
| 	ReplaceNicks           [][]string // all protocols | ||||
| 	RemoteNickFormat       string     // all protocols | ||||
| 	Server                 string     // IRC,mattermost,XMPP,discord | ||||
| 	ShowJoinPart           bool       // all protocols | ||||
| 	ShowTopicChange        bool       // slack | ||||
| 	ShowEmbeds             bool       // discord | ||||
| 	SkipTLSVerify          bool       // IRC, mattermost | ||||
| 	StripNick              bool       // all protocols | ||||
| 	Team                   string     // mattermost | ||||
| 	Token                  string     // gitter, slack, discord, api | ||||
| 	Topic                  string     // zulip | ||||
| 	URL                    string     // mattermost, slack // DEPRECATED | ||||
| 	UseAPI                 bool       // mattermost, slack | ||||
| 	UseSASL                bool       // IRC | ||||
| @@ -106,7 +126,7 @@ type Protocol struct { | ||||
| } | ||||
|  | ||||
| type ChannelOptions struct { | ||||
| 	Key        string // irc | ||||
| 	Key        string // irc, xmpp | ||||
| 	WebhookURL string // discord | ||||
| } | ||||
|  | ||||
| @@ -132,9 +152,9 @@ type SameChannelGateway struct { | ||||
| 	Accounts []string | ||||
| } | ||||
|  | ||||
| type Config struct { | ||||
| type ConfigValues struct { | ||||
| 	Api                map[string]Protocol | ||||
| 	IRC                map[string]Protocol | ||||
| 	Irc                map[string]Protocol | ||||
| 	Mattermost         map[string]Protocol | ||||
| 	Matrix             map[string]Protocol | ||||
| 	Slack              map[string]Protocol | ||||
| @@ -145,90 +165,117 @@ type Config struct { | ||||
| 	Telegram           map[string]Protocol | ||||
| 	Rocketchat         map[string]Protocol | ||||
| 	Sshchat            map[string]Protocol | ||||
| 	Zulip              map[string]Protocol | ||||
| 	General            Protocol | ||||
| 	Gateway            []Gateway | ||||
| 	SameChannelGateway []SameChannelGateway | ||||
| } | ||||
|  | ||||
| type BridgeConfig struct { | ||||
| 	Config  Protocol | ||||
| 	General *Protocol | ||||
| 	Account string | ||||
| 	Remote  chan Message | ||||
| type Config struct { | ||||
| 	v *viper.Viper | ||||
| 	*ConfigValues | ||||
| 	sync.RWMutex | ||||
| } | ||||
|  | ||||
| func NewConfig(cfgfile string) *Config { | ||||
| 	var cfg Config | ||||
| 	if _, err := toml.DecodeFile(cfgfile, &cfg); err != nil { | ||||
| 	log.SetFormatter(&prefixed.TextFormatter{PrefixPadding: 13, DisableColors: true, FullTimestamp: false}) | ||||
| 	flog := log.WithFields(log.Fields{"prefix": "config"}) | ||||
| 	var cfg ConfigValues | ||||
| 	viper.SetConfigType("toml") | ||||
| 	viper.SetConfigFile(cfgfile) | ||||
| 	viper.SetEnvPrefix("matterbridge") | ||||
| 	viper.AddConfigPath(".") | ||||
| 	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) | ||||
| 	viper.AutomaticEnv() | ||||
| 	f, err := os.Open(cfgfile) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	fail := false | ||||
| 	for k, v := range cfg.Mattermost { | ||||
| 		res := Deprecated(v, "mattermost."+k) | ||||
| 		if res { | ||||
| 			fail = res | ||||
| 		} | ||||
| 	err = viper.ReadConfig(f) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	for k, v := range cfg.Slack { | ||||
| 		res := Deprecated(v, "slack."+k) | ||||
| 		if res { | ||||
| 			fail = res | ||||
| 		} | ||||
| 	} | ||||
| 	for k, v := range cfg.Rocketchat { | ||||
| 		res := Deprecated(v, "rocketchat."+k) | ||||
| 		if res { | ||||
| 			fail = res | ||||
| 		} | ||||
| 	} | ||||
| 	if fail { | ||||
| 		log.Fatalf("Fix your config. Please see changelog for more information") | ||||
| 	err = viper.Unmarshal(&cfg) | ||||
| 	if err != nil { | ||||
| 		log.Fatal("blah", err) | ||||
| 	} | ||||
| 	mycfg := new(Config) | ||||
| 	mycfg.v = viper.GetViper() | ||||
| 	if cfg.General.MediaDownloadSize == 0 { | ||||
| 		cfg.General.MediaDownloadSize = 1000000 | ||||
| 	} | ||||
| 	return &cfg | ||||
| 	viper.WatchConfig() | ||||
| 	viper.OnConfigChange(func(e fsnotify.Event) { | ||||
| 		flog.Println("Config file changed:", e.Name) | ||||
| 	}) | ||||
|  | ||||
| 	mycfg.ConfigValues = &cfg | ||||
| 	return mycfg | ||||
| } | ||||
|  | ||||
| func OverrideCfgFromEnv(cfg *Config, protocol string, account string) { | ||||
| 	var protoCfg Protocol | ||||
| 	val := reflect.ValueOf(cfg).Elem() | ||||
| 	// loop over the Config struct | ||||
| 	for i := 0; i < val.NumField(); i++ { | ||||
| 		typeField := val.Type().Field(i) | ||||
| 		// look for the protocol map (both lowercase) | ||||
| 		if strings.ToLower(typeField.Name) == protocol { | ||||
| 			// get the Protocol struct from the map | ||||
| 			data := val.Field(i).MapIndex(reflect.ValueOf(account)) | ||||
| 			protoCfg = data.Interface().(Protocol) | ||||
| 			protoStruct := reflect.ValueOf(&protoCfg).Elem() | ||||
| 			// loop over the found protocol struct | ||||
| 			for i := 0; i < protoStruct.NumField(); i++ { | ||||
| 				typeField := protoStruct.Type().Field(i) | ||||
| 				// build our environment key (eg MATTERBRIDGE_MATTERMOST_WORK_LOGIN) | ||||
| 				key := "matterbridge_" + protocol + "_" + account + "_" + typeField.Name | ||||
| 				key = strings.ToUpper(key) | ||||
| 				// search the environment | ||||
| 				res := os.Getenv(key) | ||||
| 				// if it exists and the current field is a string | ||||
| 				// then update the current field | ||||
| 				if res != "" { | ||||
| 					fieldVal := protoStruct.Field(i) | ||||
| 					if fieldVal.Kind() == reflect.String { | ||||
| 						log.Printf("config: overriding %s from env with %s\n", key, res) | ||||
| 						fieldVal.Set(reflect.ValueOf(res)) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			// update the map with the modified Protocol (cfg.Protocol[account] = Protocol) | ||||
| 			val.Field(i).SetMapIndex(reflect.ValueOf(account), reflect.ValueOf(protoCfg)) | ||||
| 			break | ||||
| 		} | ||||
| func NewConfigFromString(input []byte) *Config { | ||||
| 	var cfg ConfigValues | ||||
| 	viper.SetConfigType("toml") | ||||
| 	err := viper.ReadConfig(bytes.NewBuffer(input)) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	err = viper.Unmarshal(&cfg) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	mycfg := new(Config) | ||||
| 	mycfg.v = viper.GetViper() | ||||
| 	mycfg.ConfigValues = &cfg | ||||
| 	return mycfg | ||||
| } | ||||
|  | ||||
| func GetIconURL(msg *Message, cfg *Protocol) string { | ||||
| 	iconURL := cfg.IconURL | ||||
| func (c *Config) GetBool(key string) bool { | ||||
| 	c.RLock() | ||||
| 	defer c.RUnlock() | ||||
| 	//	log.Debugf("getting bool %s = %#v", key, c.v.GetBool(key)) | ||||
| 	return c.v.GetBool(key) | ||||
| } | ||||
|  | ||||
| func (c *Config) GetInt(key string) int { | ||||
| 	c.RLock() | ||||
| 	defer c.RUnlock() | ||||
| 	//	log.Debugf("getting int %s = %d", key, c.v.GetInt(key)) | ||||
| 	return c.v.GetInt(key) | ||||
| } | ||||
|  | ||||
| func (c *Config) GetString(key string) string { | ||||
| 	c.RLock() | ||||
| 	defer c.RUnlock() | ||||
| 	//	log.Debugf("getting String %s = %s", key, c.v.GetString(key)) | ||||
| 	return c.v.GetString(key) | ||||
| } | ||||
|  | ||||
| func (c *Config) GetStringSlice(key string) []string { | ||||
| 	c.RLock() | ||||
| 	defer c.RUnlock() | ||||
| 	// log.Debugf("getting StringSlice %s = %#v", key, c.v.GetStringSlice(key)) | ||||
| 	return c.v.GetStringSlice(key) | ||||
| } | ||||
|  | ||||
| func (c *Config) GetStringSlice2D(key string) [][]string { | ||||
| 	c.RLock() | ||||
| 	defer c.RUnlock() | ||||
| 	result := [][]string{} | ||||
| 	if res, ok := c.v.Get(key).([]interface{}); ok { | ||||
| 		for _, entry := range res { | ||||
| 			result2 := []string{} | ||||
| 			for _, entry2 := range entry.([]interface{}) { | ||||
| 				result2 = append(result2, entry2.(string)) | ||||
| 			} | ||||
| 			result = append(result, result2) | ||||
| 		} | ||||
| 		return result | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| func GetIconURL(msg *Message, iconURL string) string { | ||||
| 	info := strings.Split(msg.Account, ".") | ||||
| 	protocol := info[0] | ||||
| 	name := info[1] | ||||
| @@ -237,17 +284,3 @@ func GetIconURL(msg *Message, cfg *Protocol) string { | ||||
| 	iconURL = strings.Replace(iconURL, "{PROTOCOL}", protocol, -1) | ||||
| 	return iconURL | ||||
| } | ||||
|  | ||||
| func Deprecated(cfg Protocol, account string) bool { | ||||
| 	if cfg.BindAddress != "" { | ||||
| 		log.Printf("ERROR: %s BindAddress is deprecated, you need to change it to WebhookBindAddress.", account) | ||||
| 	} else if cfg.URL != "" { | ||||
| 		log.Printf("ERROR: %s URL is deprecated, you need to change it to WebhookURL.", account) | ||||
| 	} else if cfg.UseAPI { | ||||
| 		log.Printf("ERROR: %s UseAPI is deprecated, it's enabled by default, please remove it from your config file.", account) | ||||
| 	} else { | ||||
| 		return false | ||||
| 	} | ||||
| 	return true | ||||
| 	//log.Fatalf("ERROR: Fix your config: %s", account) | ||||
| } | ||||
|   | ||||
| @@ -2,15 +2,20 @@ package bdiscord | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	"github.com/bwmarrin/discordgo" | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	"github.com/matterbridge/discordgo" | ||||
| ) | ||||
|  | ||||
| type bdiscord struct { | ||||
| const MessageLength = 1950 | ||||
|  | ||||
| type Bdiscord struct { | ||||
| 	c              *discordgo.Session | ||||
| 	Channels       []*discordgo.Channel | ||||
| 	Nick           string | ||||
| @@ -21,82 +26,74 @@ type bdiscord struct { | ||||
| 	webhookToken   string | ||||
| 	channelInfoMap map[string]*config.ChannelInfo | ||||
| 	sync.RWMutex | ||||
| 	*config.BridgeConfig | ||||
| 	*bridge.Config | ||||
| } | ||||
|  | ||||
| var flog *log.Entry | ||||
| var protocol = "discord" | ||||
|  | ||||
| func init() { | ||||
| 	flog = log.WithFields(log.Fields{"module": protocol}) | ||||
| } | ||||
|  | ||||
| func New(cfg *config.BridgeConfig) *bdiscord { | ||||
| 	b := &bdiscord{BridgeConfig: cfg} | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	b := &Bdiscord{Config: cfg} | ||||
| 	b.userMemberMap = make(map[string]*discordgo.Member) | ||||
| 	b.channelInfoMap = make(map[string]*config.ChannelInfo) | ||||
| 	if b.Config.WebhookURL != "" { | ||||
| 		flog.Debug("Configuring Discord Incoming Webhook") | ||||
| 		b.webhookID, b.webhookToken = b.splitURL(b.Config.WebhookURL) | ||||
| 	if b.GetString("WebhookURL") != "" { | ||||
| 		b.Log.Debug("Configuring Discord Incoming Webhook") | ||||
| 		b.webhookID, b.webhookToken = b.splitURL(b.GetString("WebhookURL")) | ||||
| 	} | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) Connect() error { | ||||
| func (b *Bdiscord) Connect() error { | ||||
| 	var err error | ||||
| 	flog.Info("Connecting") | ||||
| 	if b.Config.WebhookURL == "" { | ||||
| 		flog.Info("Connecting using token") | ||||
| 	var token string | ||||
| 	b.Log.Info("Connecting") | ||||
| 	if b.GetString("WebhookURL") == "" { | ||||
| 		b.Log.Info("Connecting using token") | ||||
| 	} else { | ||||
| 		flog.Info("Connecting using webhookurl (for posting) and token") | ||||
| 		b.Log.Info("Connecting using webhookurl (for posting) and token") | ||||
| 	} | ||||
| 	if !strings.HasPrefix(b.Config.Token, "Bot ") { | ||||
| 		b.Config.Token = "Bot " + b.Config.Token | ||||
| 	if !strings.HasPrefix(b.GetString("Token"), "Bot ") { | ||||
| 		token = "Bot " + b.GetString("Token") | ||||
| 	} | ||||
| 	b.c, err = discordgo.New(b.Config.Token) | ||||
| 	b.c, err = discordgo.New(token) | ||||
| 	if err != nil { | ||||
| 		flog.Debugf("%#v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	flog.Info("Connection succeeded") | ||||
| 	b.Log.Info("Connection succeeded") | ||||
| 	b.c.AddHandler(b.messageCreate) | ||||
| 	b.c.AddHandler(b.memberUpdate) | ||||
| 	b.c.AddHandler(b.messageUpdate) | ||||
| 	b.c.AddHandler(b.messageDelete) | ||||
| 	err = b.c.Open() | ||||
| 	if err != nil { | ||||
| 		flog.Debugf("%#v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	guilds, err := b.c.UserGuilds(100, "", "") | ||||
| 	if err != nil { | ||||
| 		flog.Debugf("%#v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	userinfo, err := b.c.User("@me") | ||||
| 	if err != nil { | ||||
| 		flog.Debugf("%#v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	b.Nick = userinfo.Username | ||||
| 	for _, guild := range guilds { | ||||
| 		if guild.Name == b.Config.Server { | ||||
| 		if guild.Name == b.GetString("Server") { | ||||
| 			b.Channels, err = b.c.GuildChannels(guild.ID) | ||||
| 			b.guildID = guild.ID | ||||
| 			if err != nil { | ||||
| 				flog.Debugf("%#v", err) | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	for _, channel := range b.Channels { | ||||
| 		b.Log.Debugf("found channel %#v", channel) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) Disconnect() error { | ||||
| 	return nil | ||||
| func (b *Bdiscord) Disconnect() error { | ||||
| 	return b.c.Close() | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) JoinChannel(channel config.ChannelInfo) error { | ||||
| func (b *Bdiscord) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	b.channelInfoMap[channel.ID] = &channel | ||||
| 	idcheck := strings.Split(channel.Name, "ID:") | ||||
| 	if len(idcheck) > 1 { | ||||
| @@ -105,99 +102,125 @@ func (b *bdiscord) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) Send(msg config.Message) (string, error) { | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| func (b *Bdiscord) Send(msg config.Message) (string, error) { | ||||
| 	b.Log.Debugf("=> Receiving %#v", msg) | ||||
|  | ||||
| 	channelID := b.getChannelID(msg.Channel) | ||||
| 	if channelID == "" { | ||||
| 		flog.Errorf("Could not find channelID for %v", msg.Channel) | ||||
| 		return "", nil | ||||
| 		return "", fmt.Errorf("Could not find channelID for %v", msg.Channel) | ||||
| 	} | ||||
|  | ||||
| 	// Make a action /me of the message | ||||
| 	if msg.Event == config.EVENT_USER_ACTION { | ||||
| 		msg.Text = "_" + msg.Text + "_" | ||||
| 	} | ||||
|  | ||||
| 	// use initial webhook | ||||
| 	wID := b.webhookID | ||||
| 	wToken := b.webhookToken | ||||
|  | ||||
| 	// check if have a channel specific webhook | ||||
| 	if ci, ok := b.channelInfoMap[msg.Channel+b.Account]; ok { | ||||
| 		if ci.Options.WebhookURL != "" { | ||||
| 			wID, wToken = b.splitURL(ci.Options.WebhookURL) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if wID == "" { | ||||
| 		flog.Debugf("Broadcasting using token (API)") | ||||
| 		if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 			if msg.ID == "" { | ||||
| 				return "", nil | ||||
| 			} | ||||
| 			err := b.c.ChannelMessageDelete(channelID, msg.ID) | ||||
| 			return "", err | ||||
| 	// Use webhook to send the message | ||||
| 	if wID != "" { | ||||
| 		// skip events | ||||
| 		if msg.Event != "" && msg.Event != config.EVENT_JOIN_LEAVE && msg.Event != config.EVENT_TOPIC_CHANGE { | ||||
| 			return "", nil | ||||
| 		} | ||||
| 		if msg.ID != "" { | ||||
| 			_, err := b.c.ChannelMessageEdit(channelID, msg.ID, msg.Username+msg.Text) | ||||
| 			return msg.ID, err | ||||
| 		} | ||||
|  | ||||
| 		if msg.Extra != nil { | ||||
| 			// check if we have files to upload (from slack, telegram or mattermost) | ||||
| 			if len(msg.Extra["file"]) > 0 { | ||||
| 				var err error | ||||
| 				for _, f := range msg.Extra["file"] { | ||||
| 					fi := f.(config.FileInfo) | ||||
| 					files := []*discordgo.File{} | ||||
| 					files = append(files, &discordgo.File{fi.Name, "", bytes.NewReader(*fi.Data)}) | ||||
| 					_, err = b.c.ChannelMessageSendComplex(channelID, &discordgo.MessageSend{Content: msg.Username + fi.Comment, Files: files}) | ||||
| 					if err != nil { | ||||
| 						flog.Errorf("file upload failed: %#v", err) | ||||
| 					} | ||||
| 				} | ||||
| 				return "", nil | ||||
| 		b.Log.Debugf("Broadcasting using Webhook") | ||||
| 		for _, f := range msg.Extra["file"] { | ||||
| 			fi := f.(config.FileInfo) | ||||
| 			if fi.URL != "" { | ||||
| 				msg.Text += " " + fi.URL | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		res, err := b.c.ChannelMessageSend(channelID, msg.Username+msg.Text) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		// skip empty messages | ||||
| 		if msg.Text == "" { | ||||
| 			return "", nil | ||||
| 		} | ||||
| 		return res.ID, err | ||||
|  | ||||
| 		msg.Text = helper.ClipMessage(msg.Text, MessageLength) | ||||
| 		err := b.c.WebhookExecute( | ||||
| 			wID, | ||||
| 			wToken, | ||||
| 			true, | ||||
| 			&discordgo.WebhookParams{ | ||||
| 				Content:   msg.Text, | ||||
| 				Username:  msg.Username, | ||||
| 				AvatarURL: msg.Avatar, | ||||
| 			}) | ||||
| 		return "", err | ||||
| 	} | ||||
| 	flog.Debugf("Broadcasting using Webhook") | ||||
| 	err := b.c.WebhookExecute( | ||||
| 		wID, | ||||
| 		wToken, | ||||
| 		true, | ||||
| 		&discordgo.WebhookParams{ | ||||
| 			Content:   msg.Text, | ||||
| 			Username:  msg.Username, | ||||
| 			AvatarURL: msg.Avatar, | ||||
| 		}) | ||||
| 	return "", err | ||||
|  | ||||
| 	b.Log.Debugf("Broadcasting using token (API)") | ||||
|  | ||||
| 	// Delete message | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		if msg.ID == "" { | ||||
| 			return "", nil | ||||
| 		} | ||||
| 		err := b.c.ChannelMessageDelete(channelID, msg.ID) | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	// Upload a file if it exists | ||||
| 	if msg.Extra != nil { | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			rmsg.Text = helper.ClipMessage(rmsg.Text, MessageLength) | ||||
| 			b.c.ChannelMessageSend(channelID, rmsg.Username+rmsg.Text) | ||||
| 		} | ||||
| 		// check if we have files to upload (from slack, telegram or mattermost) | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			return b.handleUploadFile(&msg, channelID) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	msg.Text = helper.ClipMessage(msg.Text, MessageLength) | ||||
| 	// Edit message | ||||
| 	if msg.ID != "" { | ||||
| 		_, err := b.c.ChannelMessageEdit(channelID, msg.ID, msg.Username+msg.Text) | ||||
| 		return msg.ID, err | ||||
| 	} | ||||
|  | ||||
| 	// Post normal message | ||||
| 	res, err := b.c.ChannelMessageSend(channelID, msg.Username+msg.Text) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return res.ID, err | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) messageDelete(s *discordgo.Session, m *discordgo.MessageDelete) { | ||||
| func (b *Bdiscord) messageDelete(s *discordgo.Session, m *discordgo.MessageDelete) { | ||||
| 	rmsg := config.Message{Account: b.Account, ID: m.ID, Event: config.EVENT_MSG_DELETE, Text: config.EVENT_MSG_DELETE} | ||||
| 	rmsg.Channel = b.getChannelName(m.ChannelID) | ||||
| 	if b.UseChannelID { | ||||
| 		rmsg.Channel = "ID:" + m.ChannelID | ||||
| 	} | ||||
| 	flog.Debugf("Sending message from %s to gateway", b.Account) | ||||
| 	flog.Debugf("Message is %#v", rmsg) | ||||
| 	b.Log.Debugf("<= Sending message from %s to gateway", b.Account) | ||||
| 	b.Log.Debugf("<= Message is %#v", rmsg) | ||||
| 	b.Remote <- rmsg | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) { | ||||
| 	if b.Config.EditDisable { | ||||
| func (b *Bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) { | ||||
| 	if b.GetBool("EditDisable") { | ||||
| 		return | ||||
| 	} | ||||
| 	// only when message is actually edited | ||||
| 	if m.Message.EditedTimestamp != "" { | ||||
| 		flog.Debugf("Sending edit message") | ||||
| 		m.Content = m.Content + b.Config.EditSuffix | ||||
| 		b.Log.Debugf("Sending edit message") | ||||
| 		m.Content = m.Content + b.GetString("EditSuffix") | ||||
| 		b.messageCreate(s, (*discordgo.MessageCreate)(m)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { | ||||
| func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { | ||||
| 	var err error | ||||
|  | ||||
| 	// not relay our own messages | ||||
| 	if m.Author.Username == b.Nick { | ||||
| 		return | ||||
| @@ -207,69 +230,73 @@ func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// add the url of the attachments to content | ||||
| 	if len(m.Attachments) > 0 { | ||||
| 		for _, attach := range m.Attachments { | ||||
| 			m.Content = m.Content + "\n" + attach.URL | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var text string | ||||
| 	rmsg := config.Message{Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg", UserID: m.Author.ID, ID: m.ID} | ||||
|  | ||||
| 	if m.Content != "" { | ||||
| 		flog.Debugf("Receiving message %#v", m.Message) | ||||
| 		if len(m.MentionRoles) > 0 { | ||||
| 			m.Message.Content = b.replaceRoleMentions(m.Message.Content) | ||||
| 		} | ||||
| 		b.Log.Debugf("== Receiving event %#v", m.Message) | ||||
| 		m.Message.Content = b.stripCustomoji(m.Message.Content) | ||||
| 		m.Message.Content = b.replaceChannelMentions(m.Message.Content) | ||||
| 		text = m.ContentWithMentionsReplaced() | ||||
| 		rmsg.Text, err = m.ContentWithMoreMentionsReplaced(b.c) | ||||
| 		if err != nil { | ||||
| 			b.Log.Errorf("ContentWithMoreMentionsReplaced failed: %s", err) | ||||
| 			rmsg.Text = m.ContentWithMentionsReplaced() | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	rmsg := config.Message{Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg", | ||||
| 		UserID: m.Author.ID, ID: m.ID} | ||||
|  | ||||
| 	// set channel name | ||||
| 	rmsg.Channel = b.getChannelName(m.ChannelID) | ||||
| 	if b.UseChannelID { | ||||
| 		rmsg.Channel = "ID:" + m.ChannelID | ||||
| 	} | ||||
|  | ||||
| 	if !b.Config.UseUserName { | ||||
| 	// set username | ||||
| 	if !b.GetBool("UseUserName") { | ||||
| 		rmsg.Username = b.getNick(m.Author) | ||||
| 	} else { | ||||
| 		rmsg.Username = m.Author.Username | ||||
| 	} | ||||
|  | ||||
| 	if b.Config.ShowEmbeds && m.Message.Embeds != nil { | ||||
| 	// if we have embedded content add it to text | ||||
| 	if b.GetBool("ShowEmbeds") && m.Message.Embeds != nil { | ||||
| 		for _, embed := range m.Message.Embeds { | ||||
| 			text = text + "embed: " + embed.Title + " - " + embed.Description + " - " + embed.URL + "\n" | ||||
| 			rmsg.Text = rmsg.Text + "embed: " + embed.Title + " - " + embed.Description + " - " + embed.URL + "\n" | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// no empty messages | ||||
| 	if text == "" { | ||||
| 	if rmsg.Text == "" { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	text, ok := b.replaceAction(text) | ||||
| 	// do we have a /me action | ||||
| 	var ok bool | ||||
| 	rmsg.Text, ok = b.replaceAction(rmsg.Text) | ||||
| 	if ok { | ||||
| 		rmsg.Event = config.EVENT_USER_ACTION | ||||
| 	} | ||||
|  | ||||
| 	rmsg.Text = text | ||||
| 	flog.Debugf("Sending message from %s on %s to gateway", m.Author.Username, b.Account) | ||||
| 	flog.Debugf("Message is %#v", rmsg) | ||||
| 	b.Log.Debugf("<= Sending message from %s on %s to gateway", m.Author.Username, b.Account) | ||||
| 	b.Log.Debugf("<= Message is %#v", rmsg) | ||||
| 	b.Remote <- rmsg | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) memberUpdate(s *discordgo.Session, m *discordgo.GuildMemberUpdate) { | ||||
| func (b *Bdiscord) memberUpdate(s *discordgo.Session, m *discordgo.GuildMemberUpdate) { | ||||
| 	b.Lock() | ||||
| 	if _, ok := b.userMemberMap[m.Member.User.ID]; ok { | ||||
| 		flog.Debugf("%s: memberupdate: user %s (nick %s) changes nick to %s", b.Account, m.Member.User.Username, b.userMemberMap[m.Member.User.ID].Nick, m.Member.Nick) | ||||
| 		b.Log.Debugf("%s: memberupdate: user %s (nick %s) changes nick to %s", b.Account, m.Member.User.Username, b.userMemberMap[m.Member.User.ID].Nick, m.Member.Nick) | ||||
| 	} | ||||
| 	b.userMemberMap[m.Member.User.ID] = m.Member | ||||
| 	b.Unlock() | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) getNick(user *discordgo.User) string { | ||||
| func (b *Bdiscord) getNick(user *discordgo.User) string { | ||||
| 	var err error | ||||
| 	b.Lock() | ||||
| 	defer b.Unlock() | ||||
| @@ -296,7 +323,7 @@ func (b *bdiscord) getNick(user *discordgo.User) string { | ||||
| 	return user.Username | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) getChannelID(name string) string { | ||||
| func (b *Bdiscord) getChannelID(name string) string { | ||||
| 	idcheck := strings.Split(name, "ID:") | ||||
| 	if len(idcheck) > 1 { | ||||
| 		return idcheck[1] | ||||
| @@ -309,7 +336,7 @@ func (b *bdiscord) getChannelID(name string) string { | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) getChannelName(id string) string { | ||||
| func (b *Bdiscord) getChannelName(id string) string { | ||||
| 	for _, channel := range b.Channels { | ||||
| 		if channel.ID == id { | ||||
| 			return channel.Name | ||||
| @@ -318,19 +345,7 @@ func (b *bdiscord) getChannelName(id string) string { | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) replaceRoleMentions(text string) string { | ||||
| 	roles, err := b.c.GuildRoles(b.guildID) | ||||
| 	if err != nil { | ||||
| 		flog.Debugf("%#v", string(err.(*discordgo.RESTError).ResponseBody)) | ||||
| 		return text | ||||
| 	} | ||||
| 	for _, role := range roles { | ||||
| 		text = strings.Replace(text, "<@&"+role.ID+">", "@"+role.Name, -1) | ||||
| 	} | ||||
| 	return text | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) replaceChannelMentions(text string) string { | ||||
| func (b *Bdiscord) replaceChannelMentions(text string) string { | ||||
| 	var err error | ||||
| 	re := regexp.MustCompile("<#[0-9]+>") | ||||
| 	text = re.ReplaceAllStringFunc(text, func(m string) string { | ||||
| @@ -349,28 +364,31 @@ func (b *bdiscord) replaceChannelMentions(text string) string { | ||||
| 	return text | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) replaceAction(text string) (string, bool) { | ||||
| func (b *Bdiscord) replaceAction(text string) (string, bool) { | ||||
| 	if strings.HasPrefix(text, "_") && strings.HasSuffix(text, "_") { | ||||
| 		return strings.Replace(text, "_", "", -1), true | ||||
| 	} | ||||
| 	return text, false | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) stripCustomoji(text string) string { | ||||
| func (b *Bdiscord) stripCustomoji(text string) string { | ||||
| 	// <:doge:302803592035958784> | ||||
| 	re := regexp.MustCompile("<(:.*?:)[0-9]+>") | ||||
| 	return re.ReplaceAllString(text, `$1`) | ||||
| } | ||||
|  | ||||
| // splitURL splits a webhookURL and returns the id and token | ||||
| func (b *bdiscord) splitURL(url string) (string, string) { | ||||
| func (b *Bdiscord) splitURL(url string) (string, string) { | ||||
| 	webhookURLSplit := strings.Split(url, "/") | ||||
| 	if len(webhookURLSplit) != 7 { | ||||
| 		b.Log.Fatalf("%s is no correct discord WebhookURL", url) | ||||
| 	} | ||||
| 	return webhookURLSplit[len(webhookURLSplit)-2], webhookURLSplit[len(webhookURLSplit)-1] | ||||
| } | ||||
|  | ||||
| // useWebhook returns true if we have a webhook defined somewhere | ||||
| func (b *bdiscord) useWebhook() bool { | ||||
| 	if b.Config.WebhookURL != "" { | ||||
| func (b *Bdiscord) useWebhook() bool { | ||||
| 	if b.GetString("WebhookURL") != "" { | ||||
| 		return true | ||||
| 	} | ||||
| 	for _, channel := range b.channelInfoMap { | ||||
| @@ -382,9 +400,9 @@ func (b *bdiscord) useWebhook() bool { | ||||
| } | ||||
|  | ||||
| // isWebhookID returns true if the specified id is used in a defined webhook | ||||
| func (b *bdiscord) isWebhookID(id string) bool { | ||||
| 	if b.Config.WebhookURL != "" { | ||||
| 		wID, _ := b.splitURL(b.Config.WebhookURL) | ||||
| func (b *Bdiscord) isWebhookID(id string) bool { | ||||
| 	if b.GetString("WebhookURL") != "" { | ||||
| 		wID, _ := b.splitURL(b.GetString("WebhookURL")) | ||||
| 		if wID == id { | ||||
| 			return true | ||||
| 		} | ||||
| @@ -399,3 +417,18 @@ func (b *bdiscord) isWebhookID(id string) bool { | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // handleUploadFile handles native upload of files | ||||
| func (b *Bdiscord) handleUploadFile(msg *config.Message, channelID string) (string, error) { | ||||
| 	var err error | ||||
| 	for _, f := range msg.Extra["file"] { | ||||
| 		fi := f.(config.FileInfo) | ||||
| 		files := []*discordgo.File{} | ||||
| 		files = append(files, &discordgo.File{fi.Name, "", bytes.NewReader(*fi.Data)}) | ||||
| 		_, err = b.c.ChannelMessageSendComplex(channelID, &discordgo.MessageSend{Content: msg.Username + fi.Comment, Files: files}) | ||||
| 		if err != nil { | ||||
| 			return "", fmt.Errorf("file upload failed: %#v", err) | ||||
| 		} | ||||
| 	} | ||||
| 	return "", nil | ||||
| } | ||||
|   | ||||
| @@ -2,10 +2,12 @@ package bgitter | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"github.com/42wim/go-gitter" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/42wim/go-gitter" | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| ) | ||||
|  | ||||
| type Bgitter struct { | ||||
| @@ -13,31 +15,26 @@ type Bgitter struct { | ||||
| 	User  *gitter.User | ||||
| 	Users []gitter.User | ||||
| 	Rooms []gitter.Room | ||||
| 	*config.BridgeConfig | ||||
| 	*bridge.Config | ||||
| } | ||||
|  | ||||
| var flog *log.Entry | ||||
| var protocol = "gitter" | ||||
|  | ||||
| func init() { | ||||
| 	flog = log.WithFields(log.Fields{"module": protocol}) | ||||
| } | ||||
|  | ||||
| func New(cfg *config.BridgeConfig) *Bgitter { | ||||
| 	return &Bgitter{BridgeConfig: cfg} | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	return &Bgitter{Config: cfg} | ||||
| } | ||||
|  | ||||
| func (b *Bgitter) Connect() error { | ||||
| 	var err error | ||||
| 	flog.Info("Connecting") | ||||
| 	b.c = gitter.New(b.Config.Token) | ||||
| 	b.Log.Info("Connecting") | ||||
| 	b.c = gitter.New(b.GetString("Token")) | ||||
| 	b.User, err = b.c.GetUser() | ||||
| 	if err != nil { | ||||
| 		flog.Debugf("%#v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	flog.Info("Connection succeeded") | ||||
| 	b.Rooms, _ = b.c.GetRooms() | ||||
| 	b.Rooms, err = b.c.GetRooms() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	b.Log.Info("Connection succeeded") | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @@ -73,8 +70,9 @@ func (b *Bgitter) JoinChannel(channel config.ChannelInfo) error { | ||||
| 		for event := range stream.Event { | ||||
| 			switch ev := event.Data.(type) { | ||||
| 			case *gitter.MessageReceived: | ||||
| 				// ignore message sent from ourselves | ||||
| 				if ev.Message.From.ID != b.User.ID { | ||||
| 					flog.Debugf("Sending message from %s on %s to gateway", ev.Message.From.Username, b.Account) | ||||
| 					b.Log.Debugf("<= Sending message from %s on %s to gateway", ev.Message.From.Username, b.Account) | ||||
| 					rmsg := config.Message{Username: ev.Message.From.Username, Text: ev.Message.Text, Channel: room, | ||||
| 						Account: b.Account, Avatar: b.getAvatar(ev.Message.From.Username), UserID: ev.Message.From.ID, | ||||
| 						ID: ev.Message.ID} | ||||
| @@ -82,11 +80,11 @@ func (b *Bgitter) JoinChannel(channel config.ChannelInfo) error { | ||||
| 						rmsg.Event = config.EVENT_USER_ACTION | ||||
| 						rmsg.Text = strings.Replace(rmsg.Text, "@"+ev.Message.From.Username+" ", "", -1) | ||||
| 					} | ||||
| 					flog.Debugf("Message is %#v", rmsg) | ||||
| 					b.Log.Debugf("<= Message is %#v", rmsg) | ||||
| 					b.Remote <- rmsg | ||||
| 				} | ||||
| 			case *gitter.GitterConnectionClosed: | ||||
| 				flog.Errorf("connection with gitter closed for room %s", room) | ||||
| 				b.Log.Errorf("connection with gitter closed for room %s", room) | ||||
| 			} | ||||
| 		} | ||||
| 	}(stream, room.URI) | ||||
| @@ -94,25 +92,39 @@ func (b *Bgitter) JoinChannel(channel config.ChannelInfo) error { | ||||
| } | ||||
|  | ||||
| func (b *Bgitter) Send(msg config.Message) (string, error) { | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	b.Log.Debugf("=> Receiving %#v", msg) | ||||
| 	roomID := b.getRoomID(msg.Channel) | ||||
| 	if roomID == "" { | ||||
| 		flog.Errorf("Could not find roomID for %v", msg.Channel) | ||||
| 		b.Log.Errorf("Could not find roomID for %v", msg.Channel) | ||||
| 		return "", nil | ||||
| 	} | ||||
|  | ||||
| 	// Delete message | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		if msg.ID == "" { | ||||
| 			return "", nil | ||||
| 		} | ||||
| 		// gitter has no delete message api | ||||
| 		// gitter has no delete message api so we edit message to "" | ||||
| 		_, err := b.c.UpdateMessage(roomID, msg.ID, "") | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		return "", nil | ||||
| 	} | ||||
|  | ||||
| 	// Upload a file (in gitter case send the upload URL because gitter has no native upload support) | ||||
| 	if msg.Extra != nil { | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			b.c.SendMessage(roomID, rmsg.Username+rmsg.Text) | ||||
| 		} | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			return b.handleUploadFile(&msg, roomID) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Edit message | ||||
| 	if msg.ID != "" { | ||||
| 		flog.Debugf("updating message with id %s", msg.ID) | ||||
| 		b.Log.Debugf("updating message with id %s", msg.ID) | ||||
| 		_, err := b.c.UpdateMessage(roomID, msg.ID, msg.Username+msg.Text) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| @@ -120,22 +132,7 @@ func (b *Bgitter) Send(msg config.Message) (string, error) { | ||||
| 		return "", nil | ||||
| 	} | ||||
|  | ||||
| 	if msg.Extra != nil { | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			for _, f := range msg.Extra["file"] { | ||||
| 				fi := f.(config.FileInfo) | ||||
| 				if fi.URL != "" { | ||||
| 					msg.Text = fi.URL | ||||
| 				} | ||||
| 				_, err := b.c.SendMessage(roomID, msg.Username+msg.Text) | ||||
| 				if err != nil { | ||||
| 					return "", err | ||||
| 				} | ||||
| 			} | ||||
| 			return "", nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Post normal message | ||||
| 	resp, err := b.c.SendMessage(roomID, msg.Username+msg.Text) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| @@ -163,3 +160,23 @@ func (b *Bgitter) getAvatar(user string) string { | ||||
| 	} | ||||
| 	return avatar | ||||
| } | ||||
|  | ||||
| func (b *Bgitter) handleUploadFile(msg *config.Message, roomID string) (string, error) { | ||||
| 	for _, f := range msg.Extra["file"] { | ||||
| 		fi := f.(config.FileInfo) | ||||
| 		if fi.Comment != "" { | ||||
| 			msg.Text += fi.Comment + ": " | ||||
| 		} | ||||
| 		if fi.URL != "" { | ||||
| 			msg.Text = fi.URL | ||||
| 			if fi.Comment != "" { | ||||
| 				msg.Text = fi.Comment + ": " + fi.URL | ||||
| 			} | ||||
| 		} | ||||
| 		_, err := b.c.SendMessage(roomID, msg.Username+msg.Text) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 	} | ||||
| 	return "", nil | ||||
| } | ||||
|   | ||||
| @@ -2,28 +2,41 @@ package helper | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	log "github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| func DownloadFile(url string) (*[]byte, error) { | ||||
| 	return DownloadFileAuth(url, "") | ||||
| } | ||||
|  | ||||
| func DownloadFileAuth(url string, auth string) (*[]byte, error) { | ||||
| 	var buf bytes.Buffer | ||||
| 	client := &http.Client{ | ||||
| 		Timeout: time.Second * 5, | ||||
| 	} | ||||
| 	req, err := http.NewRequest("GET", url, nil) | ||||
| 	if auth != "" { | ||||
| 		req.Header.Add("Authorization", auth) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	resp, err := client.Do(req) | ||||
| 	if err != nil { | ||||
| 		resp.Body.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	io.Copy(&buf, resp.Body) | ||||
| 	data := buf.Bytes() | ||||
| 	resp.Body.Close() | ||||
| 	return &data, nil | ||||
| } | ||||
|  | ||||
| @@ -38,3 +51,80 @@ func SplitStringLength(input string, length int) string { | ||||
| 	} | ||||
| 	return str | ||||
| } | ||||
|  | ||||
| // handle all the stuff we put into extra | ||||
| func HandleExtra(msg *config.Message, general *config.Protocol) []config.Message { | ||||
| 	extra := msg.Extra | ||||
| 	rmsg := []config.Message{} | ||||
| 	if len(extra[config.EVENT_FILE_FAILURE_SIZE]) > 0 { | ||||
| 		for _, f := range extra[config.EVENT_FILE_FAILURE_SIZE] { | ||||
| 			fi := f.(config.FileInfo) | ||||
| 			text := fmt.Sprintf("file %s too big to download (%#v > allowed size: %#v)", fi.Name, fi.Size, general.MediaDownloadSize) | ||||
| 			rmsg = append(rmsg, config.Message{Text: text, Username: "<system> ", Channel: msg.Channel, Account: msg.Account}) | ||||
| 		} | ||||
| 		return rmsg | ||||
| 	} | ||||
| 	return rmsg | ||||
| } | ||||
|  | ||||
| func GetAvatar(av map[string]string, userid string, general *config.Protocol) string { | ||||
| 	if sha, ok := av[userid]; ok { | ||||
| 		return general.MediaServerDownload + "/" + sha + "/" + userid + ".png" | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func HandleDownloadSize(flog *log.Entry, msg *config.Message, name string, size int64, general *config.Protocol) error { | ||||
| 	// check blacklist here | ||||
| 	for _, entry := range general.MediaDownloadBlackList { | ||||
| 		if entry != "" { | ||||
| 			re, err := regexp.Compile(entry) | ||||
| 			if err != nil { | ||||
| 				flog.Errorf("incorrect regexp %s for %s", entry, msg.Account) | ||||
| 				continue | ||||
| 			} | ||||
| 			if re.MatchString(name) { | ||||
| 				return fmt.Errorf("Matching blacklist %s. Not downloading %s", entry, name) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	flog.Debugf("Trying to download %#v with size %#v", name, size) | ||||
| 	if int(size) > general.MediaDownloadSize { | ||||
| 		msg.Event = config.EVENT_FILE_FAILURE_SIZE | ||||
| 		msg.Extra[msg.Event] = append(msg.Extra[msg.Event], config.FileInfo{Name: name, Comment: msg.Text, Size: size}) | ||||
| 		return fmt.Errorf("File %#v to large to download (%#v). MediaDownloadSize is %#v", name, size, general.MediaDownloadSize) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func HandleDownloadData(flog *log.Entry, msg *config.Message, name, comment, url string, data *[]byte, general *config.Protocol) { | ||||
| 	var avatar bool | ||||
| 	flog.Debugf("Download OK %#v %#v", name, len(*data)) | ||||
| 	if msg.Event == config.EVENT_AVATAR_DOWNLOAD { | ||||
| 		avatar = true | ||||
| 	} | ||||
| 	msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{Name: name, Data: data, URL: url, Comment: comment, Avatar: avatar}) | ||||
| } | ||||
|  | ||||
| func RemoveEmptyNewLines(msg string) string { | ||||
| 	lines := "" | ||||
| 	for _, line := range strings.Split(msg, "\n") { | ||||
| 		if line != "" { | ||||
| 			lines += line + "\n" | ||||
| 		} | ||||
| 	} | ||||
| 	lines = strings.TrimRight(lines, "\n") | ||||
| 	return lines | ||||
| } | ||||
|  | ||||
| func ClipMessage(text string, length int) string { | ||||
| 	// clip too long messages | ||||
| 	if len(text) > length { | ||||
| 		text = text[:length-len(" *message clipped*")] | ||||
| 		if r, size := utf8.DecodeLastRuneInString(text); r == utf8.RuneError { | ||||
| 			text = text[:len(text)-size] | ||||
| 		} | ||||
| 		text += " *message clipped*" | ||||
| 	} | ||||
| 	return text | ||||
| } | ||||
|   | ||||
| @@ -4,13 +4,7 @@ import ( | ||||
| 	"bytes" | ||||
| 	"crypto/tls" | ||||
| 	"fmt" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	"github.com/lrstanley/girc" | ||||
| 	"github.com/paulrosania/go-charset/charset" | ||||
| 	_ "github.com/paulrosania/go-charset/data" | ||||
| 	"github.com/saintfish/chardet" | ||||
| 	"hash/crc32" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net" | ||||
| @@ -19,40 +13,50 @@ import ( | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	"github.com/dfordsoft/golib/ic" | ||||
| 	"github.com/lrstanley/girc" | ||||
| 	"github.com/paulrosania/go-charset/charset" | ||||
| 	_ "github.com/paulrosania/go-charset/data" | ||||
| 	"github.com/saintfish/chardet" | ||||
| ) | ||||
|  | ||||
| type Birc struct { | ||||
| 	i               *girc.Client | ||||
| 	Nick            string | ||||
| 	names           map[string][]string | ||||
| 	connected       chan struct{} | ||||
| 	Local           chan config.Message // local queue for flood control | ||||
| 	FirstConnection bool | ||||
| 	i                                         *girc.Client | ||||
| 	Nick                                      string | ||||
| 	names                                     map[string][]string | ||||
| 	connected                                 chan struct{} | ||||
| 	Local                                     chan config.Message // local queue for flood control | ||||
| 	FirstConnection                           bool | ||||
| 	MessageDelay, MessageQueue, MessageLength int | ||||
|  | ||||
| 	*config.BridgeConfig | ||||
| 	*bridge.Config | ||||
| } | ||||
|  | ||||
| var flog *log.Entry | ||||
| var protocol = "irc" | ||||
|  | ||||
| func init() { | ||||
| 	flog = log.WithFields(log.Fields{"module": protocol}) | ||||
| } | ||||
|  | ||||
| func New(cfg *config.BridgeConfig) *Birc { | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	b := &Birc{} | ||||
| 	b.BridgeConfig = cfg | ||||
| 	b.Nick = b.Config.Nick | ||||
| 	b.Config = cfg | ||||
| 	b.Nick = b.GetString("Nick") | ||||
| 	b.names = make(map[string][]string) | ||||
| 	b.connected = make(chan struct{}) | ||||
| 	if b.Config.MessageDelay == 0 { | ||||
| 		b.Config.MessageDelay = 1300 | ||||
| 	if b.GetInt("MessageDelay") == 0 { | ||||
| 		b.MessageDelay = 1300 | ||||
| 	} else { | ||||
| 		b.MessageDelay = b.GetInt("MessageDelay") | ||||
| 	} | ||||
| 	if b.Config.MessageQueue == 0 { | ||||
| 		b.Config.MessageQueue = 30 | ||||
| 	if b.GetInt("MessageQueue") == 0 { | ||||
| 		b.MessageQueue = 30 | ||||
| 	} else { | ||||
| 		b.MessageQueue = b.GetInt("MessageQueue") | ||||
| 	} | ||||
| 	if b.Config.MessageLength == 0 { | ||||
| 		b.Config.MessageLength = 400 | ||||
| 	if b.GetInt("MessageLength") == 0 { | ||||
| 		b.MessageLength = 400 | ||||
| 	} else { | ||||
| 		b.MessageLength = b.GetInt("MessageLength") | ||||
| 	} | ||||
| 	b.FirstConnection = true | ||||
| 	return b | ||||
| @@ -69,9 +73,9 @@ func (b *Birc) Command(msg *config.Message) string { | ||||
| } | ||||
|  | ||||
| func (b *Birc) Connect() error { | ||||
| 	b.Local = make(chan config.Message, b.Config.MessageQueue+10) | ||||
| 	flog.Infof("Connecting %s", b.Config.Server) | ||||
| 	server, portstr, err := net.SplitHostPort(b.Config.Server) | ||||
| 	b.Local = make(chan config.Message, b.MessageQueue+10) | ||||
| 	b.Log.Infof("Connecting %s", b.GetString("Server")) | ||||
| 	server, portstr, err := net.SplitHostPort(b.GetString("Server")) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -80,7 +84,7 @@ func (b *Birc) Connect() error { | ||||
| 		return err | ||||
| 	} | ||||
| 	// fix strict user handling of girc | ||||
| 	user := b.Config.Nick | ||||
| 	user := b.GetString("Nick") | ||||
| 	for !girc.IsValidUser(user) { | ||||
| 		if len(user) == 1 { | ||||
| 			user = "matterbridge" | ||||
| @@ -91,62 +95,65 @@ func (b *Birc) Connect() error { | ||||
|  | ||||
| 	i := girc.New(girc.Config{ | ||||
| 		Server:     server, | ||||
| 		ServerPass: b.Config.Password, | ||||
| 		ServerPass: b.GetString("Password"), | ||||
| 		Port:       port, | ||||
| 		Nick:       b.Config.Nick, | ||||
| 		Nick:       b.GetString("Nick"), | ||||
| 		User:       user, | ||||
| 		Name:       b.Config.Nick, | ||||
| 		SSL:        b.Config.UseTLS, | ||||
| 		TLSConfig:  &tls.Config{InsecureSkipVerify: b.Config.SkipTLSVerify, ServerName: server}, | ||||
| 		Name:       b.GetString("Nick"), | ||||
| 		SSL:        b.GetBool("UseTLS"), | ||||
| 		TLSConfig:  &tls.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), ServerName: server}, | ||||
| 		PingDelay:  time.Minute, | ||||
| 	}) | ||||
|  | ||||
| 	if b.Config.UseSASL { | ||||
| 		i.Config.SASL = &girc.SASLPlain{b.Config.NickServNick, b.Config.NickServPassword} | ||||
| 	if b.GetBool("UseSASL") { | ||||
| 		i.Config.SASL = &girc.SASLPlain{b.GetString("NickServNick"), b.GetString("NickServPassword")} | ||||
| 	} | ||||
|  | ||||
| 	i.Handlers.Add(girc.RPL_WELCOME, b.handleNewConnection) | ||||
| 	i.Handlers.Add(girc.RPL_ENDOFMOTD, b.handleOtherAuth) | ||||
| 	i.Handlers.Add("*", b.handleOther) | ||||
| 	i.Handlers.Add(girc.ALL_EVENTS, b.handleOther) | ||||
| 	go func() { | ||||
| 		for { | ||||
| 			if err := i.Connect(); err != nil { | ||||
| 				flog.Errorf("error: %s", err) | ||||
| 				flog.Info("reconnecting in 30 seconds...") | ||||
| 				time.Sleep(30 * time.Second) | ||||
| 				i.Handlers.Clear(girc.RPL_WELCOME) | ||||
| 				i.Handlers.Add(girc.RPL_WELCOME, func(client *girc.Client, event girc.Event) { | ||||
| 					b.Remote <- config.Message{Username: "system", Text: "rejoin", Channel: "", Account: b.Account, Event: config.EVENT_REJOIN_CHANNELS} | ||||
| 					// set our correct nick on reconnect if necessary | ||||
| 					b.Nick = event.Source.Name | ||||
| 				}) | ||||
| 				b.Log.Errorf("disconnect: error: %s", err) | ||||
| 			} else { | ||||
| 				return | ||||
| 				b.Log.Info("disconnect: client requested quit") | ||||
| 			} | ||||
|  | ||||
| 			b.Log.Info("reconnecting in 30 seconds...") | ||||
| 			time.Sleep(30 * time.Second) | ||||
| 			i.Handlers.Clear(girc.RPL_WELCOME) | ||||
| 			i.Handlers.Add(girc.RPL_WELCOME, func(client *girc.Client, event girc.Event) { | ||||
| 				b.Remote <- config.Message{Username: "system", Text: "rejoin", Channel: "", Account: b.Account, Event: config.EVENT_REJOIN_CHANNELS} | ||||
| 				// set our correct nick on reconnect if necessary | ||||
| 				b.Nick = event.Source.Name | ||||
| 			}) | ||||
| 		} | ||||
| 	}() | ||||
| 	b.i = i | ||||
| 	select { | ||||
| 	case <-b.connected: | ||||
| 		flog.Info("Connection succeeded") | ||||
| 		b.Log.Info("Connection succeeded") | ||||
| 	case <-time.After(time.Second * 30): | ||||
| 		return fmt.Errorf("connection timed out") | ||||
| 	} | ||||
| 	//i.Debug = false | ||||
| 	i.Handlers.Clear("*") | ||||
| 	if b.GetInt("DebugLevel") == 0 { | ||||
| 		i.Handlers.Clear(girc.ALL_EVENTS) | ||||
| 	} | ||||
| 	go b.doSend() | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Birc) Disconnect() error { | ||||
| 	//b.i.Disconnect() | ||||
| 	b.i.Close() | ||||
| 	close(b.Local) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Birc) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	if channel.Options.Key != "" { | ||||
| 		flog.Debugf("using key %s for channel %s", channel.Options.Key, channel.Name) | ||||
| 		b.Log.Debugf("using key %s for channel %s", channel.Options.Key, channel.Name) | ||||
| 		b.i.Cmd.JoinKey(channel.Name, channel.Options.Key) | ||||
| 	} else { | ||||
| 		b.i.Cmd.Join(channel.Name) | ||||
| @@ -159,29 +166,53 @@ func (b *Birc) Send(msg config.Message) (string, error) { | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
|  | ||||
| 	b.Log.Debugf("=> Receiving %#v", msg) | ||||
|  | ||||
| 	// we can be in between reconnects #385 | ||||
| 	if !b.i.IsConnected() { | ||||
| 		b.Log.Error("Not connected to server, dropping message") | ||||
| 	} | ||||
|  | ||||
| 	// Execute a command | ||||
| 	if strings.HasPrefix(msg.Text, "!") { | ||||
| 		b.Command(&msg) | ||||
| 	} | ||||
|  | ||||
| 	if b.Config.Charset != "" { | ||||
| 		buf := new(bytes.Buffer) | ||||
| 		w, err := charset.NewWriter(b.Config.Charset, buf) | ||||
| 		if err != nil { | ||||
| 			flog.Errorf("charset from utf-8 conversion failed: %s", err) | ||||
| 			return "", err | ||||
| 	// convert to specified charset | ||||
| 	if b.GetString("Charset") != "" { | ||||
| 		switch b.GetString("Charset") { | ||||
| 		case "gbk", "gb18030", "gb2312", "big5", "euc-kr", "euc-jp", "shift-jis", "iso-2022-jp": | ||||
| 			msg.Text = ic.ConvertString("utf-8", b.GetString("Charset"), msg.Text) | ||||
| 		default: | ||||
| 			buf := new(bytes.Buffer) | ||||
| 			w, err := charset.NewWriter(b.GetString("Charset"), buf) | ||||
| 			if err != nil { | ||||
| 				b.Log.Errorf("charset from utf-8 conversion failed: %s", err) | ||||
| 				return "", err | ||||
| 			} | ||||
| 			fmt.Fprint(w, msg.Text) | ||||
| 			w.Close() | ||||
| 			msg.Text = buf.String() | ||||
| 		} | ||||
| 		fmt.Fprintf(w, msg.Text) | ||||
| 		w.Close() | ||||
| 		msg.Text = buf.String() | ||||
| 	} | ||||
|  | ||||
| 	// Handle files | ||||
| 	if msg.Extra != nil { | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			b.Local <- rmsg | ||||
| 		} | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			for _, f := range msg.Extra["file"] { | ||||
| 				fi := f.(config.FileInfo) | ||||
| 				if fi.Comment != "" { | ||||
| 					msg.Text += fi.Comment + ": " | ||||
| 				} | ||||
| 				if fi.URL != "" { | ||||
| 					msg.Text = fi.URL | ||||
| 					if fi.Comment != "" { | ||||
| 						msg.Text = fi.Comment + ": " + fi.URL | ||||
| 					} | ||||
| 				} | ||||
| 				b.Local <- config.Message{Text: msg.Text, Username: msg.Username, Channel: msg.Channel, Event: msg.Event} | ||||
| 			} | ||||
| @@ -190,35 +221,45 @@ func (b *Birc) Send(msg config.Message) (string, error) { | ||||
| 	} | ||||
|  | ||||
| 	// split long messages on messageLength, to avoid clipped messages #281 | ||||
| 	if b.Config.MessageSplit { | ||||
| 		msg.Text = helper.SplitStringLength(msg.Text, b.Config.MessageLength) | ||||
| 	if b.GetBool("MessageSplit") { | ||||
| 		msg.Text = helper.SplitStringLength(msg.Text, b.MessageLength) | ||||
| 	} | ||||
| 	for _, text := range strings.Split(msg.Text, "\n") { | ||||
| 		input := []rune(text) | ||||
| 		if len(text) > b.Config.MessageLength { | ||||
| 			text = string(input[:b.Config.MessageLength]) + " <message clipped>" | ||||
| 		if len(text) > b.MessageLength { | ||||
| 			text = text[:b.MessageLength-len(" <message clipped>")] | ||||
| 			if r, size := utf8.DecodeLastRuneInString(text); r == utf8.RuneError { | ||||
| 				text = text[:len(text)-size] | ||||
| 			} | ||||
| 			text += " <message clipped>" | ||||
| 		} | ||||
| 		if len(b.Local) < b.Config.MessageQueue { | ||||
| 			if len(b.Local) == b.Config.MessageQueue-1 { | ||||
| 		if len(b.Local) < b.MessageQueue { | ||||
| 			if len(b.Local) == b.MessageQueue-1 { | ||||
| 				text = text + " <message clipped>" | ||||
| 			} | ||||
| 			b.Local <- config.Message{Text: text, Username: msg.Username, Channel: msg.Channel, Event: msg.Event} | ||||
| 		} else { | ||||
| 			flog.Debugf("flooding, dropping message (queue at %d)", len(b.Local)) | ||||
| 			b.Log.Debugf("flooding, dropping message (queue at %d)", len(b.Local)) | ||||
| 		} | ||||
| 	} | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| func (b *Birc) doSend() { | ||||
| 	rate := time.Millisecond * time.Duration(b.Config.MessageDelay) | ||||
| 	rate := time.Millisecond * time.Duration(b.MessageDelay) | ||||
| 	throttle := time.NewTicker(rate) | ||||
| 	for msg := range b.Local { | ||||
| 		<-throttle.C | ||||
| 		username := msg.Username | ||||
| 		if b.GetBool("Colornicks") { | ||||
| 			checksum := crc32.ChecksumIEEE([]byte(msg.Username)) | ||||
| 			colorCode := checksum%14 + 2 // quick fix - prevent white or black color codes | ||||
| 			username = fmt.Sprintf("\x03%02d%s\x0F", colorCode, msg.Username) | ||||
| 		} | ||||
| 		if msg.Event == config.EVENT_USER_ACTION { | ||||
| 			b.i.Cmd.Action(msg.Channel, msg.Username+msg.Text) | ||||
| 			b.i.Cmd.Action(msg.Channel, username+msg.Text) | ||||
| 		} else { | ||||
| 			b.i.Cmd.Message(msg.Channel, msg.Username+msg.Text) | ||||
| 			b.Log.Debugf("Sending to channel %s", msg.Channel) | ||||
| 			b.i.Cmd.Message(msg.Channel, username+msg.Text) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -242,7 +283,7 @@ func (b *Birc) endNames(client *girc.Client, event girc.Event) { | ||||
| } | ||||
|  | ||||
| func (b *Birc) handleNewConnection(client *girc.Client, event girc.Event) { | ||||
| 	flog.Debug("Registering callbacks") | ||||
| 	b.Log.Debug("Registering callbacks") | ||||
| 	i := b.i | ||||
| 	b.Nick = event.Params[0] | ||||
|  | ||||
| @@ -261,107 +302,138 @@ func (b *Birc) handleNewConnection(client *girc.Client, event girc.Event) { | ||||
|  | ||||
| func (b *Birc) handleJoinPart(client *girc.Client, event girc.Event) { | ||||
| 	if len(event.Params) == 0 { | ||||
| 		flog.Debugf("handleJoinPart: empty Params? %#v", event) | ||||
| 		b.Log.Debugf("handleJoinPart: empty Params? %#v", event) | ||||
| 		return | ||||
| 	} | ||||
| 	channel := event.Params[0] | ||||
| 	channel := strings.ToLower(event.Params[0]) | ||||
| 	if event.Command == "KICK" { | ||||
| 		flog.Infof("Got kicked from %s by %s", channel, event.Source.Name) | ||||
| 		time.Sleep(time.Duration(b.Config.RejoinDelay) * time.Second) | ||||
| 		b.Log.Infof("Got kicked from %s by %s", channel, event.Source.Name) | ||||
| 		time.Sleep(time.Duration(b.GetInt("RejoinDelay")) * time.Second) | ||||
| 		b.Remote <- config.Message{Username: "system", Text: "rejoin", Channel: channel, Account: b.Account, Event: config.EVENT_REJOIN_CHANNELS} | ||||
| 		return | ||||
| 	} | ||||
| 	if event.Command == "QUIT" { | ||||
| 		if event.Source.Name == b.Nick && strings.Contains(event.Trailing, "Ping timeout") { | ||||
| 			flog.Infof("%s reconnecting ..", b.Account) | ||||
| 			b.Log.Infof("%s reconnecting ..", b.Account) | ||||
| 			b.Remote <- config.Message{Username: "system", Text: "reconnect", Channel: channel, Account: b.Account, Event: config.EVENT_FAILURE} | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	if event.Source.Name != b.Nick { | ||||
| 		flog.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account) | ||||
| 		b.Remote <- config.Message{Username: "system", Text: event.Source.Name + " " + strings.ToLower(event.Command) + "s", Channel: channel, Account: b.Account, Event: config.EVENT_JOIN_LEAVE} | ||||
| 		if b.GetBool("nosendjoinpart") { | ||||
| 			return | ||||
| 		} | ||||
| 		b.Log.Debugf("<= Sending JOIN_LEAVE event from %s to gateway", b.Account) | ||||
| 		msg := config.Message{Username: "system", Text: event.Source.Name + " " + strings.ToLower(event.Command) + "s", Channel: channel, Account: b.Account, Event: config.EVENT_JOIN_LEAVE} | ||||
| 		b.Log.Debugf("<= Message is %#v", msg) | ||||
| 		b.Remote <- msg | ||||
| 		return | ||||
| 	} | ||||
| 	flog.Debugf("handle %#v", event) | ||||
| 	b.Log.Debugf("handle %#v", event) | ||||
| } | ||||
|  | ||||
| func (b *Birc) handleNotice(client *girc.Client, event girc.Event) { | ||||
| 	if strings.Contains(event.String(), "This nickname is registered") && event.Source.Name == b.Config.NickServNick { | ||||
| 		b.i.Cmd.Message(b.Config.NickServNick, "IDENTIFY "+b.Config.NickServPassword) | ||||
| 	if strings.Contains(event.String(), "This nickname is registered") && event.Source.Name == b.GetString("NickServNick") { | ||||
| 		b.Log.Debugf("Sending identify to nickserv %s", b.GetString("NickServNick")) | ||||
| 		b.i.Cmd.Message(b.GetString("NickServNick"), "IDENTIFY "+b.GetString("NickServPassword")) | ||||
| 	} else { | ||||
| 		b.handlePrivMsg(client, event) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Birc) handleOther(client *girc.Client, event girc.Event) { | ||||
| 	if b.GetInt("DebugLevel") == 1 { | ||||
| 		if event.Command != "CLIENT_STATE_UPDATED" && | ||||
| 			event.Command != "CLIENT_GENERAL_UPDATED" { | ||||
| 			b.Log.Debugf("%#v", event.String()) | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	switch event.Command { | ||||
| 	case "372", "375", "376", "250", "251", "252", "253", "254", "255", "265", "266", "002", "003", "004", "005": | ||||
| 		return | ||||
| 	} | ||||
| 	flog.Debugf("%#v", event.String()) | ||||
| 	b.Log.Debugf("%#v", event.String()) | ||||
| } | ||||
|  | ||||
| func (b *Birc) handleOtherAuth(client *girc.Client, event girc.Event) { | ||||
| 	if strings.EqualFold(b.Config.NickServNick, "Q@CServe.quakenet.org") { | ||||
| 		flog.Debugf("Authenticating %s against %s", b.Config.NickServUsername, b.Config.NickServNick) | ||||
| 		b.i.Cmd.Message(b.Config.NickServNick, "AUTH "+b.Config.NickServUsername+" "+b.Config.NickServPassword) | ||||
| 	if strings.EqualFold(b.GetString("NickServNick"), "Q@CServe.quakenet.org") { | ||||
| 		b.Log.Debugf("Authenticating %s against %s", b.GetString("NickServUsername"), b.GetString("NickServNick")) | ||||
| 		b.i.Cmd.Message(b.GetString("NickServNick"), "AUTH "+b.GetString("NickServUsername")+" "+b.GetString("NickServPassword")) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Birc) handlePrivMsg(client *girc.Client, event girc.Event) { | ||||
| func (b *Birc) skipPrivMsg(event girc.Event) bool { | ||||
| 	// Our nick can be changed | ||||
| 	b.Nick = b.i.GetNick() | ||||
|  | ||||
| 	// freenode doesn't send 001 as first reply | ||||
| 	if event.Command == "NOTICE" { | ||||
| 		return | ||||
| 		return true | ||||
| 	} | ||||
| 	// don't forward queries to the bot | ||||
| 	if event.Params[0] == b.Nick { | ||||
| 		return | ||||
| 		return true | ||||
| 	} | ||||
| 	// don't forward message from ourself | ||||
| 	if event.Source.Name == b.Nick { | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (b *Birc) handlePrivMsg(client *girc.Client, event girc.Event) { | ||||
| 	if b.skipPrivMsg(event) { | ||||
| 		return | ||||
| 	} | ||||
| 	rmsg := config.Message{Username: event.Source.Name, Channel: strings.ToLower(event.Params[0]), Account: b.Account, UserID: event.Source.Ident + "@" + event.Source.Host} | ||||
| 	flog.Debugf("handlePrivMsg() %s %s %#v", event.Source.Name, event.Trailing, event) | ||||
| 	msg := "" | ||||
| 	b.Log.Debugf("== Receiving PRIVMSG: %s %s %#v", event.Source.Name, event.Trailing, event) | ||||
|  | ||||
| 	// set action event | ||||
| 	if event.IsAction() { | ||||
| 		rmsg.Event = config.EVENT_USER_ACTION | ||||
| 	} | ||||
| 	msg += event.StripAction() | ||||
| 	// strip IRC colors | ||||
| 	re := regexp.MustCompile(`[[:cntrl:]](?:\d{1,2}(?:,\d{1,2})?)?`) | ||||
| 	msg = re.ReplaceAllString(msg, "") | ||||
|  | ||||
| 	// strip action, we made an event if it was an action | ||||
| 	rmsg.Text += event.StripAction() | ||||
|  | ||||
| 	// strip IRC colors | ||||
| 	re := regexp.MustCompile(`\x03(?:\d{1,2}(?:,\d{1,2})?)?|[[:cntrl:]]`) | ||||
| 	rmsg.Text = re.ReplaceAllString(rmsg.Text, "") | ||||
|  | ||||
| 	// start detecting the charset | ||||
| 	var r io.Reader | ||||
| 	var err error | ||||
| 	mycharset := b.Config.Charset | ||||
| 	mycharset := b.GetString("Charset") | ||||
| 	if mycharset == "" { | ||||
| 		// detect what were sending so that we convert it to utf-8 | ||||
| 		detector := chardet.NewTextDetector() | ||||
| 		result, err := detector.DetectBest([]byte(msg)) | ||||
| 		result, err := detector.DetectBest([]byte(rmsg.Text)) | ||||
| 		if err != nil { | ||||
| 			flog.Infof("detection failed for msg: %#v", msg) | ||||
| 			b.Log.Infof("detection failed for rmsg.Text: %#v", rmsg.Text) | ||||
| 			return | ||||
| 		} | ||||
| 		flog.Debugf("detected %s confidence %#v", result.Charset, result.Confidence) | ||||
| 		b.Log.Debugf("detected %s confidence %#v", result.Charset, result.Confidence) | ||||
| 		mycharset = result.Charset | ||||
| 		// if we're not sure, just pick ISO-8859-1 | ||||
| 		if result.Confidence < 80 { | ||||
| 			mycharset = "ISO-8859-1" | ||||
| 		} | ||||
| 	} | ||||
| 	r, err = charset.NewReader(mycharset, strings.NewReader(msg)) | ||||
| 	if err != nil { | ||||
| 		flog.Errorf("charset to utf-8 conversion failed: %s", err) | ||||
| 		return | ||||
| 	switch mycharset { | ||||
| 	case "gbk", "gb18030", "gb2312", "big5", "euc-kr", "euc-jp", "shift-jis", "iso-2022-jp": | ||||
| 		rmsg.Text = ic.ConvertString("utf-8", b.GetString("Charset"), rmsg.Text) | ||||
| 	default: | ||||
| 		r, err = charset.NewReader(mycharset, strings.NewReader(rmsg.Text)) | ||||
| 		if err != nil { | ||||
| 			b.Log.Errorf("charset to utf-8 conversion failed: %s", err) | ||||
| 			return | ||||
| 		} | ||||
| 		output, _ := ioutil.ReadAll(r) | ||||
| 		rmsg.Text = string(output) | ||||
| 	} | ||||
| 	output, _ := ioutil.ReadAll(r) | ||||
| 	msg = string(output) | ||||
|  | ||||
| 	flog.Debugf("Sending message from %s on %s to gateway", event.Params[0], b.Account) | ||||
| 	rmsg.Text = msg | ||||
| 	b.Log.Debugf("<= Sending message from %s on %s to gateway", event.Params[0], b.Account) | ||||
| 	b.Remote <- rmsg | ||||
| } | ||||
|  | ||||
| @@ -369,13 +441,13 @@ func (b *Birc) handleTopicWhoTime(client *girc.Client, event girc.Event) { | ||||
| 	parts := strings.Split(event.Params[2], "!") | ||||
| 	t, err := strconv.ParseInt(event.Params[3], 10, 64) | ||||
| 	if err != nil { | ||||
| 		flog.Errorf("Invalid time stamp: %s", event.Params[3]) | ||||
| 		b.Log.Errorf("Invalid time stamp: %s", event.Params[3]) | ||||
| 	} | ||||
| 	user := parts[0] | ||||
| 	if len(parts) > 1 { | ||||
| 		user += " [" + parts[1] + "]" | ||||
| 	} | ||||
| 	flog.Debugf("%s: Topic set by %s [%s]", event.Command, user, time.Unix(t, 0)) | ||||
| 	b.Log.Debugf("%s: Topic set by %s [%s]", event.Command, user, time.Unix(t, 0)) | ||||
| } | ||||
|  | ||||
| func (b *Birc) nicksPerRow() int { | ||||
|   | ||||
| @@ -2,14 +2,15 @@ package bmatrix | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"mime" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	matrix "github.com/matterbridge/gomatrix" | ||||
| ) | ||||
|  | ||||
| @@ -18,42 +19,33 @@ type Bmatrix struct { | ||||
| 	UserID  string | ||||
| 	RoomMap map[string]string | ||||
| 	sync.RWMutex | ||||
| 	*config.BridgeConfig | ||||
| 	*bridge.Config | ||||
| } | ||||
|  | ||||
| var flog *log.Entry | ||||
| var protocol = "matrix" | ||||
|  | ||||
| func init() { | ||||
| 	flog = log.WithFields(log.Fields{"module": protocol}) | ||||
| } | ||||
|  | ||||
| func New(cfg *config.BridgeConfig) *Bmatrix { | ||||
| 	b := &Bmatrix{BridgeConfig: cfg} | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	b := &Bmatrix{Config: cfg} | ||||
| 	b.RoomMap = make(map[string]string) | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| func (b *Bmatrix) Connect() error { | ||||
| 	var err error | ||||
| 	flog.Infof("Connecting %s", b.Config.Server) | ||||
| 	b.mc, err = matrix.NewClient(b.Config.Server, "", "") | ||||
| 	b.Log.Infof("Connecting %s", b.GetString("Server")) | ||||
| 	b.mc, err = matrix.NewClient(b.GetString("Server"), "", "") | ||||
| 	if err != nil { | ||||
| 		flog.Debugf("%#v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	resp, err := b.mc.Login(&matrix.ReqLogin{ | ||||
| 		Type:     "m.login.password", | ||||
| 		User:     b.Config.Login, | ||||
| 		Password: b.Config.Password, | ||||
| 		User:     b.GetString("Login"), | ||||
| 		Password: b.GetString("Password"), | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		flog.Debugf("%#v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	b.mc.SetCredentials(resp.UserID, resp.AccessToken) | ||||
| 	b.UserID = resp.UserID | ||||
| 	flog.Info("Connection succeeded") | ||||
| 	b.Log.Info("Connection succeeded") | ||||
| 	go b.handlematrix() | ||||
| 	return nil | ||||
| } | ||||
| @@ -74,9 +66,22 @@ func (b *Bmatrix) JoinChannel(channel config.ChannelInfo) error { | ||||
| } | ||||
|  | ||||
| func (b *Bmatrix) Send(msg config.Message) (string, error) { | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	b.Log.Debugf("=> Receiving %#v", msg) | ||||
|  | ||||
| 	channel := b.getRoomID(msg.Channel) | ||||
| 	// ignore delete messages | ||||
| 	b.Log.Debugf("Channel %s maps to channel id %s", msg.Channel, channel) | ||||
|  | ||||
| 	// Make a action /me of the message | ||||
| 	if msg.Event == config.EVENT_USER_ACTION { | ||||
| 		resp, err := b.mc.SendMessageEvent(channel, "m.room.message", | ||||
| 			matrix.TextMessage{"m.emote", msg.Username + msg.Text}) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		return resp.EventID, err | ||||
| 	} | ||||
|  | ||||
| 	// Delete message | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		if msg.ID == "" { | ||||
| 			return "", nil | ||||
| @@ -87,53 +92,22 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) { | ||||
| 		} | ||||
| 		return resp.EventID, err | ||||
| 	} | ||||
| 	flog.Debugf("Sending to channel %s", channel) | ||||
| 	if msg.Event == config.EVENT_USER_ACTION { | ||||
| 		resp, err := b.mc.SendMessageEvent(channel, "m.room.message", | ||||
| 			matrix.TextMessage{"m.emote", msg.Username + msg.Text}) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		return resp.EventID, err | ||||
| 	} | ||||
|  | ||||
| 	// Upload a file if it exists | ||||
| 	if msg.Extra != nil { | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			b.mc.SendText(channel, rmsg.Username+rmsg.Text) | ||||
| 		} | ||||
| 		// check if we have files to upload (from slack, telegram or mattermost) | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			for _, f := range msg.Extra["file"] { | ||||
| 				fi := f.(config.FileInfo) | ||||
| 				content := bytes.NewReader(*fi.Data) | ||||
| 				sp := strings.Split(fi.Name, ".") | ||||
| 				mtype := mime.TypeByExtension("." + sp[len(sp)-1]) | ||||
| 				if strings.Contains(mtype, "image") || | ||||
| 					strings.Contains(mtype, "video") { | ||||
| 					flog.Debugf("uploading file: %s %s", fi.Name, mtype) | ||||
| 					res, err := b.mc.UploadToContentRepo(content, mtype, int64(len(*fi.Data))) | ||||
| 					if err != nil { | ||||
| 						flog.Errorf("file upload failed: %#v", err) | ||||
| 						continue | ||||
| 					} | ||||
| 					if strings.Contains(mtype, "video") { | ||||
| 						flog.Debugf("sendVideo %s", res.ContentURI) | ||||
| 						_, err = b.mc.SendVideo(channel, fi.Name, res.ContentURI) | ||||
| 						if err != nil { | ||||
| 							flog.Errorf("sendVideo failed: %#v", err) | ||||
| 						} | ||||
| 					} | ||||
| 					if strings.Contains(mtype, "image") { | ||||
| 						flog.Debugf("sendImage %s", res.ContentURI) | ||||
| 						_, err = b.mc.SendImage(channel, fi.Name, res.ContentURI) | ||||
| 						if err != nil { | ||||
| 							flog.Errorf("sendImage failed: %#v", err) | ||||
| 						} | ||||
| 					} | ||||
| 					flog.Debugf("result: %#v", res) | ||||
| 				} | ||||
| 			} | ||||
| 			return "", nil | ||||
| 			return b.handleUploadFile(&msg, channel) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Edit message if we have an ID | ||||
| 	// matrix has no editing support | ||||
|  | ||||
| 	// Post normal message | ||||
| 	resp, err := b.mc.SendText(channel, msg.Username+msg.Text) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| @@ -159,7 +133,7 @@ func (b *Bmatrix) handlematrix() error { | ||||
| 	go func() { | ||||
| 		for { | ||||
| 			if err := b.mc.Sync(); err != nil { | ||||
| 				flog.Println("Sync() returned ", err) | ||||
| 				b.Log.Println("Sync() returned ", err) | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
| @@ -167,24 +141,34 @@ func (b *Bmatrix) handlematrix() error { | ||||
| } | ||||
|  | ||||
| func (b *Bmatrix) handleEvent(ev *matrix.Event) { | ||||
| 	flog.Debugf("Received: %#v", ev) | ||||
| 	b.Log.Debugf("== Receiving event: %#v", ev) | ||||
| 	if ev.Sender != b.UserID { | ||||
| 		b.RLock() | ||||
| 		channel, ok := b.RoomMap[ev.RoomID] | ||||
| 		b.RUnlock() | ||||
| 		if !ok { | ||||
| 			flog.Debugf("Unknown room %s", ev.RoomID) | ||||
| 			b.Log.Debugf("Unknown room %s", ev.RoomID) | ||||
| 			return | ||||
| 		} | ||||
| 		username := ev.Sender[1:] | ||||
| 		if b.Config.NoHomeServerSuffix { | ||||
| 			re := regexp.MustCompile("(.*?):.*") | ||||
| 			username = re.ReplaceAllString(username, `$1`) | ||||
|  | ||||
| 		// TODO download avatar | ||||
|  | ||||
| 		// Create our message | ||||
| 		rmsg := config.Message{Username: ev.Sender[1:], Channel: channel, Account: b.Account, UserID: ev.Sender, ID: ev.ID} | ||||
|  | ||||
| 		// Text must be a string | ||||
| 		if rmsg.Text, ok = ev.Content["body"].(string); !ok { | ||||
| 			b.Log.Errorf("Content[body] wasn't a %T ?", rmsg.Text) | ||||
| 			return | ||||
| 		} | ||||
| 		var text string | ||||
| 		text, _ = ev.Content["body"].(string) | ||||
| 		rmsg := config.Message{Username: username, Text: text, Channel: channel, Account: b.Account, UserID: ev.Sender} | ||||
| 		rmsg.ID = ev.ID | ||||
|  | ||||
| 		// Remove homeserver suffix if configured | ||||
| 		if b.GetBool("NoHomeServerSuffix") { | ||||
| 			re := regexp.MustCompile("(.*?):.*") | ||||
| 			rmsg.Username = re.ReplaceAllString(rmsg.Username, `$1`) | ||||
| 		} | ||||
|  | ||||
| 		// Delete event | ||||
| 		if ev.Type == "m.room.redaction" { | ||||
| 			rmsg.Event = config.EVENT_MSG_DELETE | ||||
| 			rmsg.ID = ev.Redacts | ||||
| @@ -192,46 +176,137 @@ func (b *Bmatrix) handleEvent(ev *matrix.Event) { | ||||
| 			b.Remote <- rmsg | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		// Do we have a /me action | ||||
| 		if ev.Content["msgtype"].(string) == "m.emote" { | ||||
| 			rmsg.Event = config.EVENT_USER_ACTION | ||||
| 		} | ||||
| 		if ev.Content["msgtype"] != nil && ev.Content["msgtype"].(string) == "m.image" || | ||||
| 			ev.Content["msgtype"].(string) == "m.video" || | ||||
| 			ev.Content["msgtype"].(string) == "m.file" { | ||||
| 			flog.Debugf("ev: %#v", ev) | ||||
| 			rmsg.Extra = make(map[string][]interface{}) | ||||
| 			url := ev.Content["url"].(string) | ||||
| 			url = strings.Replace(url, "mxc://", b.Config.Server+"/_matrix/media/v1/download/", -1) | ||||
| 			info := ev.Content["info"].(map[string]interface{}) | ||||
| 			size := info["size"].(float64) | ||||
| 			name := ev.Content["body"].(string) | ||||
| 			// check if we have an image uploaded without extension | ||||
| 			if !strings.Contains(name, ".") { | ||||
| 				if ev.Content["msgtype"].(string) == "m.image" { | ||||
| 					if mtype, ok := ev.Content["mimetype"].(string); ok { | ||||
| 						mext, _ := mime.ExtensionsByType(mtype) | ||||
| 						if len(mext) > 0 { | ||||
| 							name = name + mext[0] | ||||
| 						} | ||||
| 					} else { | ||||
| 						// just a default .png extension if we don't have mime info | ||||
| 						name = name + ".png" | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 		// Do we have attachments | ||||
| 		if b.containsAttachment(ev.Content) { | ||||
| 			err := b.handleDownloadFile(&rmsg, ev.Content) | ||||
| 			if err != nil { | ||||
| 				b.Log.Errorf("download failed: %#v", err) | ||||
| 			} | ||||
| 			flog.Debugf("trying to download %#v with size %#v", name, size) | ||||
| 			if size <= float64(b.General.MediaDownloadSize) { | ||||
| 				data, err := helper.DownloadFile(url) | ||||
| 				if err != nil { | ||||
| 					flog.Errorf("download %s failed %#v", url, err) | ||||
| 				} else { | ||||
| 					flog.Debugf("download OK %#v %#v %#v", name, len(*data), len(url)) | ||||
| 					rmsg.Extra["file"] = append(rmsg.Extra["file"], config.FileInfo{Name: name, Data: data}) | ||||
| 				} | ||||
| 			} | ||||
| 			rmsg.Text = "" | ||||
| 		} | ||||
| 		flog.Debugf("Sending message from %s on %s to gateway", ev.Sender, b.Account) | ||||
|  | ||||
| 		b.Log.Debugf("<= Sending message from %s on %s to gateway", ev.Sender, b.Account) | ||||
| 		b.Remote <- rmsg | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // handleDownloadFile handles file download | ||||
| func (b *Bmatrix) handleDownloadFile(rmsg *config.Message, content map[string]interface{}) error { | ||||
| 	var ( | ||||
| 		ok                        bool | ||||
| 		url, name, msgtype, mtype string | ||||
| 		info                      map[string]interface{} | ||||
| 		size                      float64 | ||||
| 	) | ||||
|  | ||||
| 	rmsg.Extra = make(map[string][]interface{}) | ||||
| 	if url, ok = content["url"].(string); !ok { | ||||
| 		return fmt.Errorf("url isn't a %T", url) | ||||
| 	} | ||||
| 	url = strings.Replace(url, "mxc://", b.GetString("Server")+"/_matrix/media/v1/download/", -1) | ||||
|  | ||||
| 	if info, ok = content["info"].(map[string]interface{}); !ok { | ||||
| 		return fmt.Errorf("info isn't a %T", info) | ||||
| 	} | ||||
| 	if size, ok = info["size"].(float64); !ok { | ||||
| 		return fmt.Errorf("size isn't a %T", size) | ||||
| 	} | ||||
| 	if name, ok = content["body"].(string); !ok { | ||||
| 		return fmt.Errorf("name isn't a %T", name) | ||||
| 	} | ||||
| 	if msgtype, ok = content["msgtype"].(string); !ok { | ||||
| 		return fmt.Errorf("msgtype isn't a %T", msgtype) | ||||
| 	} | ||||
| 	if mtype, ok = info["mimetype"].(string); !ok { | ||||
| 		return fmt.Errorf("mtype isn't a %T", mtype) | ||||
| 	} | ||||
|  | ||||
| 	// check if we have an image uploaded without extension | ||||
| 	if !strings.Contains(name, ".") { | ||||
| 		if msgtype == "m.image" { | ||||
| 			mext, _ := mime.ExtensionsByType(mtype) | ||||
| 			if len(mext) > 0 { | ||||
| 				name = name + mext[0] | ||||
| 			} | ||||
| 		} else { | ||||
| 			// just a default .png extension if we don't have mime info | ||||
| 			name = name + ".png" | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// check if the size is ok | ||||
| 	err := helper.HandleDownloadSize(b.Log, rmsg, name, int64(size), b.General) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	// actually download the file | ||||
| 	data, err := helper.DownloadFile(url) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("download %s failed %#v", url, err) | ||||
| 	} | ||||
| 	// add the downloaded data to the message | ||||
| 	helper.HandleDownloadData(b.Log, rmsg, name, "", url, data, b.General) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // handleUploadFile handles native upload of files | ||||
| func (b *Bmatrix) handleUploadFile(msg *config.Message, channel string) (string, error) { | ||||
| 	for _, f := range msg.Extra["file"] { | ||||
| 		fi := f.(config.FileInfo) | ||||
| 		content := bytes.NewReader(*fi.Data) | ||||
| 		sp := strings.Split(fi.Name, ".") | ||||
| 		mtype := mime.TypeByExtension("." + sp[len(sp)-1]) | ||||
| 		if strings.Contains(mtype, "image") || | ||||
| 			strings.Contains(mtype, "video") { | ||||
| 			if fi.Comment != "" { | ||||
| 				_, err := b.mc.SendText(channel, msg.Username+fi.Comment) | ||||
| 				if err != nil { | ||||
| 					b.Log.Errorf("file comment failed: %#v", err) | ||||
| 				} | ||||
| 			} | ||||
| 			b.Log.Debugf("uploading file: %s %s", fi.Name, mtype) | ||||
| 			res, err := b.mc.UploadToContentRepo(content, mtype, int64(len(*fi.Data))) | ||||
| 			if err != nil { | ||||
| 				b.Log.Errorf("file upload failed: %#v", err) | ||||
| 				continue | ||||
| 			} | ||||
| 			if strings.Contains(mtype, "video") { | ||||
| 				b.Log.Debugf("sendVideo %s", res.ContentURI) | ||||
| 				_, err = b.mc.SendVideo(channel, fi.Name, res.ContentURI) | ||||
| 				if err != nil { | ||||
| 					b.Log.Errorf("sendVideo failed: %#v", err) | ||||
| 				} | ||||
| 			} | ||||
| 			if strings.Contains(mtype, "image") { | ||||
| 				b.Log.Debugf("sendImage %s", res.ContentURI) | ||||
| 				_, err = b.mc.SendImage(channel, fi.Name, res.ContentURI) | ||||
| 				if err != nil { | ||||
| 					b.Log.Errorf("sendImage failed: %#v", err) | ||||
| 				} | ||||
| 			} | ||||
| 			b.Log.Debugf("result: %#v", res) | ||||
| 		} | ||||
| 	} | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| // skipMessages returns true if this message should not be handled | ||||
| func (b *Bmatrix) containsAttachment(content map[string]interface{}) bool { | ||||
| 	// Skip empty messages | ||||
| 	if content["msgtype"] == nil { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	// Only allow image,video or file msgtypes | ||||
| 	if !(content["msgtype"].(string) == "m.image" || | ||||
| 		content["msgtype"].(string) == "m.video" || | ||||
| 		content["msgtype"].(string) == "m.file") { | ||||
| 		return false | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|   | ||||
| @@ -3,49 +3,28 @@ package bmattermost | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	"github.com/42wim/matterbridge/matterclient" | ||||
| 	"github.com/42wim/matterbridge/matterhook" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	"strings" | ||||
| 	"github.com/rs/xid" | ||||
| ) | ||||
|  | ||||
| type MMhook struct { | ||||
| 	mh *matterhook.Client | ||||
| } | ||||
|  | ||||
| type MMapi struct { | ||||
| 	mc    *matterclient.MMClient | ||||
| 	mmMap map[string]string | ||||
| } | ||||
|  | ||||
| type MMMessage struct { | ||||
| 	Text     string | ||||
| 	Channel  string | ||||
| 	Username string | ||||
| 	UserID   string | ||||
| 	ID       string | ||||
| 	Event    string | ||||
| 	Extra    map[string][]interface{} | ||||
| } | ||||
|  | ||||
| type Bmattermost struct { | ||||
| 	MMhook | ||||
| 	MMapi | ||||
| 	TeamId string | ||||
| 	*config.BridgeConfig | ||||
| 	mh     *matterhook.Client | ||||
| 	mc     *matterclient.MMClient | ||||
| 	uuid   string | ||||
| 	TeamID string | ||||
| 	*bridge.Config | ||||
| 	avatarMap map[string]string | ||||
| } | ||||
|  | ||||
| var flog *log.Entry | ||||
| var protocol = "mattermost" | ||||
|  | ||||
| func init() { | ||||
| 	flog = log.WithFields(log.Fields{"module": protocol}) | ||||
| } | ||||
|  | ||||
| func New(cfg *config.BridgeConfig) *Bmattermost { | ||||
| 	b := &Bmattermost{BridgeConfig: cfg} | ||||
| 	b.mmMap = make(map[string]string) | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	b := &Bmattermost{Config: cfg, avatarMap: make(map[string]string)} | ||||
| 	b.uuid = xid.New().String() | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| @@ -54,47 +33,47 @@ func (b *Bmattermost) Command(cmd string) string { | ||||
| } | ||||
|  | ||||
| func (b *Bmattermost) Connect() error { | ||||
| 	if b.Config.WebhookBindAddress != "" { | ||||
| 		if b.Config.WebhookURL != "" { | ||||
| 			flog.Info("Connecting using webhookurl (sending) and webhookbindaddress (receiving)") | ||||
| 			b.mh = matterhook.New(b.Config.WebhookURL, | ||||
| 				matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify, | ||||
| 					BindAddress: b.Config.WebhookBindAddress}) | ||||
| 		} else if b.Config.Token != "" { | ||||
| 			flog.Info("Connecting using token (sending)") | ||||
| 	if b.GetString("WebhookBindAddress") != "" { | ||||
| 		if b.GetString("WebhookURL") != "" { | ||||
| 			b.Log.Info("Connecting using webhookurl (sending) and webhookbindaddress (receiving)") | ||||
| 			b.mh = matterhook.New(b.GetString("WebhookURL"), | ||||
| 				matterhook.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), | ||||
| 					BindAddress: b.GetString("WebhookBindAddress")}) | ||||
| 		} else if b.GetString("Token") != "" { | ||||
| 			b.Log.Info("Connecting using token (sending)") | ||||
| 			err := b.apiLogin() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} else if b.Config.Login != "" { | ||||
| 			flog.Info("Connecting using login/password (sending)") | ||||
| 		} else if b.GetString("Login") != "" { | ||||
| 			b.Log.Info("Connecting using login/password (sending)") | ||||
| 			err := b.apiLogin() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} else { | ||||
| 			flog.Info("Connecting using webhookbindaddress (receiving)") | ||||
| 			b.mh = matterhook.New(b.Config.WebhookURL, | ||||
| 				matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify, | ||||
| 					BindAddress: b.Config.WebhookBindAddress}) | ||||
| 			b.Log.Info("Connecting using webhookbindaddress (receiving)") | ||||
| 			b.mh = matterhook.New(b.GetString("WebhookURL"), | ||||
| 				matterhook.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), | ||||
| 					BindAddress: b.GetString("WebhookBindAddress")}) | ||||
| 		} | ||||
| 		go b.handleMatter() | ||||
| 		return nil | ||||
| 	} | ||||
| 	if b.Config.WebhookURL != "" { | ||||
| 		flog.Info("Connecting using webhookurl (sending)") | ||||
| 		b.mh = matterhook.New(b.Config.WebhookURL, | ||||
| 			matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify, | ||||
| 	if b.GetString("WebhookURL") != "" { | ||||
| 		b.Log.Info("Connecting using webhookurl (sending)") | ||||
| 		b.mh = matterhook.New(b.GetString("WebhookURL"), | ||||
| 			matterhook.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), | ||||
| 				DisableServer: true}) | ||||
| 		if b.Config.Token != "" { | ||||
| 			flog.Info("Connecting using token (receiving)") | ||||
| 		if b.GetString("Token") != "" { | ||||
| 			b.Log.Info("Connecting using token (receiving)") | ||||
| 			err := b.apiLogin() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			go b.handleMatter() | ||||
| 		} else if b.Config.Login != "" { | ||||
| 			flog.Info("Connecting using login/password (receiving)") | ||||
| 		} else if b.GetString("Login") != "" { | ||||
| 			b.Log.Info("Connecting using login/password (receiving)") | ||||
| 			err := b.apiLogin() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| @@ -102,23 +81,23 @@ func (b *Bmattermost) Connect() error { | ||||
| 			go b.handleMatter() | ||||
| 		} | ||||
| 		return nil | ||||
| 	} else if b.Config.Token != "" { | ||||
| 		flog.Info("Connecting using token (sending and receiving)") | ||||
| 	} else if b.GetString("Token") != "" { | ||||
| 		b.Log.Info("Connecting using token (sending and receiving)") | ||||
| 		err := b.apiLogin() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		go b.handleMatter() | ||||
| 	} else if b.Config.Login != "" { | ||||
| 		flog.Info("Connecting using login/password (sending and receiving)") | ||||
| 	} else if b.GetString("Login") != "" { | ||||
| 		b.Log.Info("Connecting using login/password (sending and receiving)") | ||||
| 		err := b.apiLogin() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		go b.handleMatter() | ||||
| 	} | ||||
| 	if b.Config.WebhookBindAddress == "" && b.Config.WebhookURL == "" && b.Config.Login == "" && b.Config.Token == "" { | ||||
| 		return errors.New("No connection method found. See that you have WebhookBindAddress, WebhookURL or Token/Login/Password/Server/Team configured.") | ||||
| 	if b.GetString("WebhookBindAddress") == "" && b.GetString("WebhookURL") == "" && b.GetString("Login") == "" && b.GetString("Token") == "" { | ||||
| 		return errors.New("no connection method found. See that you have WebhookBindAddress, WebhookURL or Token/Login/Password/Server/Team configured") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| @@ -129,7 +108,7 @@ func (b *Bmattermost) Disconnect() error { | ||||
|  | ||||
| func (b *Bmattermost) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	// we can only join channels using the API | ||||
| 	if b.Config.WebhookURL == "" && b.Config.WebhookBindAddress == "" { | ||||
| 	if b.GetString("WebhookURL") == "" && b.GetString("WebhookBindAddress") == "" { | ||||
| 		id := b.mc.GetChannelId(channel.Name, "") | ||||
| 		if id == "" { | ||||
| 			return fmt.Errorf("Could not find channel ID for channel %s", channel.Name) | ||||
| @@ -140,189 +119,347 @@ func (b *Bmattermost) JoinChannel(channel config.ChannelInfo) error { | ||||
| } | ||||
|  | ||||
| func (b *Bmattermost) Send(msg config.Message) (string, error) { | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	b.Log.Debugf("=> Receiving %#v", msg) | ||||
|  | ||||
| 	// Make a action /me of the message | ||||
| 	if msg.Event == config.EVENT_USER_ACTION { | ||||
| 		msg.Text = "*" + msg.Text + "*" | ||||
| 	} | ||||
| 	nick := msg.Username | ||||
| 	message := msg.Text | ||||
| 	channel := msg.Channel | ||||
|  | ||||
| 	if b.Config.PrefixMessagesWithNick { | ||||
| 		message = nick + message | ||||
| 	// map the file SHA to our user (caches the avatar) | ||||
| 	if msg.Event == config.EVENT_AVATAR_DOWNLOAD { | ||||
| 		return b.cacheAvatar(&msg) | ||||
| 	} | ||||
| 	if b.Config.WebhookURL != "" { | ||||
| 		matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL} | ||||
| 		matterMessage.IconURL = msg.Avatar | ||||
| 		matterMessage.Channel = channel | ||||
| 		matterMessage.UserName = nick | ||||
| 		matterMessage.Type = "" | ||||
| 		matterMessage.Text = message | ||||
| 		matterMessage.Text = message | ||||
| 		matterMessage.Props = make(map[string]interface{}) | ||||
| 		matterMessage.Props["matterbridge"] = true | ||||
| 		err := b.mh.Send(matterMessage) | ||||
| 		if err != nil { | ||||
| 			flog.Info(err) | ||||
| 			return "", err | ||||
| 		} | ||||
| 		return "", nil | ||||
|  | ||||
| 	// Use webhook to send the message | ||||
| 	if b.GetString("WebhookURL") != "" { | ||||
| 		return b.sendWebhook(msg) | ||||
| 	} | ||||
|  | ||||
| 	// Delete message | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		if msg.ID == "" { | ||||
| 			return "", nil | ||||
| 		} | ||||
| 		return msg.ID, b.mc.DeleteMessage(msg.ID) | ||||
| 	} | ||||
|  | ||||
| 	// Upload a file if it exists | ||||
| 	if msg.Extra != nil { | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			b.mc.PostMessage(b.mc.GetChannelId(rmsg.Channel, ""), rmsg.Username+rmsg.Text) | ||||
| 		} | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			var err error | ||||
| 			var res, id string | ||||
| 			for _, f := range msg.Extra["file"] { | ||||
| 				fi := f.(config.FileInfo) | ||||
| 				id, err = b.mc.UploadFile(*fi.Data, b.mc.GetChannelId(channel, ""), fi.Name) | ||||
| 				if err != nil { | ||||
| 					flog.Debugf("ERROR %#v", err) | ||||
| 					return "", err | ||||
| 				} | ||||
| 				message = fi.Comment | ||||
| 				if b.Config.PrefixMessagesWithNick { | ||||
| 					message = nick + fi.Comment | ||||
| 				} | ||||
| 				res, err = b.mc.PostMessageWithFiles(b.mc.GetChannelId(channel, ""), message, []string{id}) | ||||
| 			} | ||||
| 			return res, err | ||||
| 			return b.handleUploadFile(&msg) | ||||
| 		} | ||||
| 	} | ||||
| 	if msg.ID != "" { | ||||
| 		return b.mc.EditMessage(msg.ID, message) | ||||
|  | ||||
| 	// Prepend nick if configured | ||||
| 	if b.GetBool("PrefixMessagesWithNick") { | ||||
| 		msg.Text = msg.Username + msg.Text | ||||
| 	} | ||||
| 	return b.mc.PostMessage(b.mc.GetChannelId(channel, ""), message) | ||||
|  | ||||
| 	// Edit message if we have an ID | ||||
| 	if msg.ID != "" { | ||||
| 		return b.mc.EditMessage(msg.ID, msg.Text) | ||||
| 	} | ||||
|  | ||||
| 	// Post normal message | ||||
| 	return b.mc.PostMessage(b.mc.GetChannelId(msg.Channel, ""), msg.Text) | ||||
| } | ||||
|  | ||||
| func (b *Bmattermost) handleMatter() { | ||||
| 	mchan := make(chan *MMMessage) | ||||
| 	if b.Config.WebhookBindAddress != "" { | ||||
| 		flog.Debugf("Choosing webhooks based receiving") | ||||
| 		go b.handleMatterHook(mchan) | ||||
| 	messages := make(chan *config.Message) | ||||
| 	if b.GetString("WebhookBindAddress") != "" { | ||||
| 		b.Log.Debugf("Choosing webhooks based receiving") | ||||
| 		go b.handleMatterHook(messages) | ||||
| 	} else { | ||||
| 		if b.Config.Token != "" { | ||||
| 			flog.Debugf("Choosing token based receiving") | ||||
| 		if b.GetString("Token") != "" { | ||||
| 			b.Log.Debugf("Choosing token based receiving") | ||||
| 		} else { | ||||
| 			flog.Debugf("Choosing login/password based receiving") | ||||
| 			b.Log.Debugf("Choosing login/password based receiving") | ||||
| 		} | ||||
| 		go b.handleMatterClient(mchan) | ||||
| 		go b.handleMatterClient(messages) | ||||
| 	} | ||||
| 	for message := range mchan { | ||||
| 		rmsg := config.Message{Username: message.Username, Channel: message.Channel, Account: b.Account, UserID: message.UserID, ID: message.ID, Event: message.Event, Extra: message.Extra} | ||||
| 		text, ok := b.replaceAction(message.Text) | ||||
| 		if ok { | ||||
| 			rmsg.Event = config.EVENT_USER_ACTION | ||||
| 	var ok bool | ||||
| 	for message := range messages { | ||||
| 		message.Avatar = helper.GetAvatar(b.avatarMap, message.UserID, b.General) | ||||
| 		message.Account = b.Account | ||||
| 		if nick := b.mc.GetNickName(message.UserID); nick != "" { | ||||
| 			message.Username = nick | ||||
| 		} | ||||
| 		rmsg.Text = text | ||||
| 		flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account) | ||||
| 		flog.Debugf("Message is %#v", rmsg) | ||||
| 		b.Remote <- rmsg | ||||
| 		message.Text, ok = b.replaceAction(message.Text) | ||||
| 		if ok { | ||||
| 			message.Event = config.EVENT_USER_ACTION | ||||
| 		} | ||||
| 		b.Log.Debugf("<= Sending message from %s on %s to gateway", message.Username, b.Account) | ||||
| 		b.Log.Debugf("<= Message is %#v", message) | ||||
| 		b.Remote <- *message | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) { | ||||
| func (b *Bmattermost) handleMatterClient(messages chan *config.Message) { | ||||
| 	for message := range b.mc.MessageChan { | ||||
| 		flog.Debugf("%#v", message.Raw.Data) | ||||
| 		if message.Type == "system_join_leave" || | ||||
| 			message.Type == "system_join_channel" || | ||||
| 			message.Type == "system_leave_channel" { | ||||
| 			flog.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account) | ||||
| 			b.Remote <- config.Message{Username: "system", Text: message.Text, Channel: message.Channel, Account: b.Account, Event: config.EVENT_JOIN_LEAVE} | ||||
| 			continue | ||||
| 		} | ||||
| 		if (message.Raw.Event == "post_edited") && b.Config.EditDisable { | ||||
| 		b.Log.Debugf("%#v", message.Raw.Data) | ||||
|  | ||||
| 		if b.skipMessage(message) { | ||||
| 			b.Log.Debugf("Skipped message: %#v", message) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		m := &MMMessage{Extra: make(map[string][]interface{})} | ||||
| 		// only download avatars if we have a place to upload them (configured mediaserver) | ||||
| 		if b.General.MediaServerUpload != "" || b.General.MediaDownloadPath != "" { | ||||
| 			b.handleDownloadAvatar(message.UserID, message.Channel) | ||||
| 		} | ||||
|  | ||||
| 		b.Log.Debugf("== Receiving event %#v", message) | ||||
|  | ||||
| 		rmsg := &config.Message{Username: message.Username, UserID: message.UserID, Channel: message.Channel, Text: message.Text, ID: message.Post.Id, Extra: make(map[string][]interface{})} | ||||
|  | ||||
| 		// handle mattermost post properties (override username and attachments) | ||||
| 		props := message.Post.Props | ||||
| 		if props != nil { | ||||
| 			if _, ok := props["matterbridge"].(bool); ok { | ||||
| 				flog.Debugf("sent by matterbridge, ignoring") | ||||
| 				continue | ||||
| 			} | ||||
| 			if _, ok := props["override_username"].(string); ok { | ||||
| 				message.Username = props["override_username"].(string) | ||||
| 				rmsg.Username = props["override_username"].(string) | ||||
| 			} | ||||
| 			if _, ok := props["attachments"].([]interface{}); ok { | ||||
| 				m.Extra["attachments"] = props["attachments"].([]interface{}) | ||||
| 			} | ||||
| 		} | ||||
| 		// do not post our own messages back to irc | ||||
| 		// only listen to message from our team | ||||
| 		if (message.Raw.Event == "posted" || message.Raw.Event == "post_edited" || message.Raw.Event == "post_deleted") && | ||||
| 			b.mc.User.Username != message.Username && message.Raw.Data["team_id"].(string) == b.TeamId { | ||||
| 			// if the message has reactions don't repost it (for now, until we can correlate reaction with message) | ||||
| 			if message.Post.HasReactions { | ||||
| 				continue | ||||
| 			} | ||||
| 			flog.Debugf("Receiving from matterclient %#v", message) | ||||
| 			m.UserID = message.UserID | ||||
| 			m.Username = message.Username | ||||
| 			m.Channel = message.Channel | ||||
| 			m.Text = message.Text | ||||
| 			m.ID = message.Post.Id | ||||
| 			if message.Raw.Event == "post_edited" && !b.Config.EditDisable { | ||||
| 				m.Text = message.Text + b.Config.EditSuffix | ||||
| 			} | ||||
| 			if message.Raw.Event == "post_deleted" { | ||||
| 				m.Event = config.EVENT_MSG_DELETE | ||||
| 			} | ||||
| 			if len(message.Post.FileIds) > 0 { | ||||
| 				for _, link := range b.mc.GetFileLinks(message.Post.FileIds) { | ||||
| 					m.Text = m.Text + "\n" + link | ||||
| 				rmsg.Extra["attachments"] = props["attachments"].([]interface{}) | ||||
| 				if rmsg.Text == "" { | ||||
| 					for _, attachment := range rmsg.Extra["attachments"] { | ||||
| 						attach := attachment.(map[string]interface{}) | ||||
| 						if attach["text"].(string) != "" { | ||||
| 							rmsg.Text += attach["text"].(string) | ||||
| 							continue | ||||
| 						} | ||||
| 						if attach["fallback"].(string) != "" { | ||||
| 							rmsg.Text += attach["fallback"].(string) | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			mchan <- m | ||||
| 		} | ||||
|  | ||||
| 		// create a text for bridges that don't support native editing | ||||
| 		if message.Raw.Event == "post_edited" && !b.GetBool("EditDisable") { | ||||
| 			rmsg.Text = message.Text + b.GetString("EditSuffix") | ||||
| 		} | ||||
|  | ||||
| 		if message.Raw.Event == "post_deleted" { | ||||
| 			rmsg.Event = config.EVENT_MSG_DELETE | ||||
| 		} | ||||
|  | ||||
| 		if len(message.Post.FileIds) > 0 { | ||||
| 			for _, id := range message.Post.FileIds { | ||||
| 				err := b.handleDownloadFile(rmsg, id) | ||||
| 				if err != nil { | ||||
| 					b.Log.Errorf("download failed: %s", err) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		messages <- rmsg | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Bmattermost) handleMatterHook(mchan chan *MMMessage) { | ||||
| func (b *Bmattermost) handleMatterHook(messages chan *config.Message) { | ||||
| 	for { | ||||
| 		message := b.mh.Receive() | ||||
| 		flog.Debugf("Receiving from matterhook %#v", message) | ||||
| 		m := &MMMessage{} | ||||
| 		m.UserID = message.UserID | ||||
| 		m.Username = message.UserName | ||||
| 		m.Text = message.Text | ||||
| 		m.Channel = message.ChannelName | ||||
| 		mchan <- m | ||||
| 		b.Log.Debugf("Receiving from matterhook %#v", message) | ||||
| 		messages <- &config.Message{UserID: message.UserID, Username: message.UserName, Text: message.Text, Channel: message.ChannelName} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Bmattermost) apiLogin() error { | ||||
| 	password := b.Config.Password | ||||
| 	if b.Config.Token != "" { | ||||
| 		password = "MMAUTHTOKEN=" + b.Config.Token | ||||
| 	password := b.GetString("Password") | ||||
| 	if b.GetString("Token") != "" { | ||||
| 		password = "MMAUTHTOKEN=" + b.GetString("Token") | ||||
| 	} | ||||
|  | ||||
| 	b.mc = matterclient.New(b.Config.Login, password, | ||||
| 		b.Config.Team, b.Config.Server) | ||||
| 	b.mc.SkipTLSVerify = b.Config.SkipTLSVerify | ||||
| 	b.mc.NoTLS = b.Config.NoTLS | ||||
| 	flog.Infof("Connecting %s (team: %s) on %s", b.Config.Login, b.Config.Team, b.Config.Server) | ||||
| 	b.mc = matterclient.New(b.GetString("Login"), password, b.GetString("Team"), b.GetString("Server")) | ||||
| 	if b.GetBool("debug") { | ||||
| 		b.mc.SetLogLevel("debug") | ||||
| 	} | ||||
| 	b.mc.SkipTLSVerify = b.GetBool("SkipTLSVerify") | ||||
| 	b.mc.NoTLS = b.GetBool("NoTLS") | ||||
| 	b.Log.Infof("Connecting %s (team: %s) on %s", b.GetString("Login"), b.GetString("Team"), b.GetString("Server")) | ||||
| 	err := b.mc.Login() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	flog.Info("Connection succeeded") | ||||
| 	b.TeamId = b.mc.GetTeamId() | ||||
| 	b.Log.Info("Connection succeeded") | ||||
| 	b.TeamID = b.mc.GetTeamId() | ||||
| 	go b.mc.WsReceiver() | ||||
| 	go b.mc.StatusLoop() | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // replaceAction replace the message with the correct action (/me) code | ||||
| func (b *Bmattermost) replaceAction(text string) (string, bool) { | ||||
| 	if strings.HasPrefix(text, "*") && strings.HasSuffix(text, "*") { | ||||
| 		return strings.Replace(text, "*", "", -1), true | ||||
| 	} | ||||
| 	return text, false | ||||
| } | ||||
|  | ||||
| func (b *Bmattermost) cacheAvatar(msg *config.Message) (string, error) { | ||||
| 	fi := msg.Extra["file"][0].(config.FileInfo) | ||||
| 	/* if we have a sha we have successfully uploaded the file to the media server, | ||||
| 	so we can now cache the sha */ | ||||
| 	if fi.SHA != "" { | ||||
| 		b.Log.Debugf("Added %s to %s in avatarMap", fi.SHA, msg.UserID) | ||||
| 		b.avatarMap[msg.UserID] = fi.SHA | ||||
| 	} | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| // handleDownloadAvatar downloads the avatar of userid from channel | ||||
| // sends a EVENT_AVATAR_DOWNLOAD message to the gateway if successful. | ||||
| // logs an error message if it fails | ||||
| func (b *Bmattermost) handleDownloadAvatar(userid string, channel string) { | ||||
| 	rmsg := config.Message{Username: "system", Text: "avatar", Channel: channel, Account: b.Account, UserID: userid, Event: config.EVENT_AVATAR_DOWNLOAD, Extra: make(map[string][]interface{})} | ||||
| 	if _, ok := b.avatarMap[userid]; !ok { | ||||
| 		data, resp := b.mc.Client.GetProfileImage(userid, "") | ||||
| 		if resp.Error != nil { | ||||
| 			b.Log.Errorf("ProfileImage download failed for %#v %s", userid, resp.Error) | ||||
| 			return | ||||
| 		} | ||||
| 		err := helper.HandleDownloadSize(b.Log, &rmsg, userid+".png", int64(len(data)), b.General) | ||||
| 		if err != nil { | ||||
| 			b.Log.Error(err) | ||||
| 			return | ||||
| 		} | ||||
| 		helper.HandleDownloadData(b.Log, &rmsg, userid+".png", rmsg.Text, "", &data, b.General) | ||||
| 		b.Remote <- rmsg | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // handleDownloadFile handles file download | ||||
| func (b *Bmattermost) handleDownloadFile(rmsg *config.Message, id string) error { | ||||
| 	url, _ := b.mc.Client.GetFileLink(id) | ||||
| 	finfo, resp := b.mc.Client.GetFileInfo(id) | ||||
| 	if resp.Error != nil { | ||||
| 		return resp.Error | ||||
| 	} | ||||
| 	err := helper.HandleDownloadSize(b.Log, rmsg, finfo.Name, finfo.Size, b.General) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	data, resp := b.mc.Client.DownloadFile(id, true) | ||||
| 	if resp.Error != nil { | ||||
| 		return resp.Error | ||||
| 	} | ||||
| 	helper.HandleDownloadData(b.Log, rmsg, finfo.Name, rmsg.Text, url, &data, b.General) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // handleUploadFile handles native upload of files | ||||
| func (b *Bmattermost) handleUploadFile(msg *config.Message) (string, error) { | ||||
| 	var err error | ||||
| 	var res, id string | ||||
| 	channelID := b.mc.GetChannelId(msg.Channel, "") | ||||
| 	for _, f := range msg.Extra["file"] { | ||||
| 		fi := f.(config.FileInfo) | ||||
| 		id, err = b.mc.UploadFile(*fi.Data, channelID, fi.Name) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		msg.Text = fi.Comment | ||||
| 		if b.GetBool("PrefixMessagesWithNick") { | ||||
| 			msg.Text = msg.Username + msg.Text | ||||
| 		} | ||||
| 		res, err = b.mc.PostMessageWithFiles(channelID, msg.Text, []string{id}) | ||||
| 	} | ||||
| 	return res, err | ||||
| } | ||||
|  | ||||
| // sendWebhook uses the configured WebhookURL to send the message | ||||
| func (b *Bmattermost) sendWebhook(msg config.Message) (string, error) { | ||||
| 	// skip events | ||||
| 	if msg.Event != "" { | ||||
| 		return "", nil | ||||
| 	} | ||||
|  | ||||
| 	if b.GetBool("PrefixMessagesWithNick") { | ||||
| 		msg.Text = msg.Username + msg.Text | ||||
| 	} | ||||
| 	if msg.Extra != nil { | ||||
| 		// this sends a message only if we received a config.EVENT_FILE_FAILURE_SIZE | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			iconURL := config.GetIconURL(&rmsg, b.GetString("iconurl")) | ||||
| 			matterMessage := matterhook.OMessage{IconURL: iconURL, Channel: rmsg.Channel, UserName: rmsg.Username, Text: rmsg.Text, Props: make(map[string]interface{})} | ||||
| 			matterMessage.Props["matterbridge_"+b.uuid] = true | ||||
| 			b.mh.Send(matterMessage) | ||||
| 		} | ||||
|  | ||||
| 		// webhook doesn't support file uploads, so we add the url manually | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			for _, f := range msg.Extra["file"] { | ||||
| 				fi := f.(config.FileInfo) | ||||
| 				if fi.URL != "" { | ||||
| 					msg.Text += fi.URL | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	iconURL := config.GetIconURL(&msg, b.GetString("iconurl")) | ||||
| 	matterMessage := matterhook.OMessage{IconURL: iconURL, Channel: msg.Channel, UserName: msg.Username, Text: msg.Text, Props: make(map[string]interface{})} | ||||
| 	if msg.Avatar != "" { | ||||
| 		matterMessage.IconURL = msg.Avatar | ||||
| 	} | ||||
| 	matterMessage.Props["matterbridge_"+b.uuid] = true | ||||
| 	err := b.mh.Send(matterMessage) | ||||
| 	if err != nil { | ||||
| 		b.Log.Info(err) | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| // skipMessages returns true if this message should not be handled | ||||
| func (b *Bmattermost) skipMessage(message *matterclient.Message) bool { | ||||
| 	// Handle join/leave | ||||
| 	if message.Type == "system_join_leave" || | ||||
| 		message.Type == "system_join_channel" || | ||||
| 		message.Type == "system_leave_channel" { | ||||
| 		if b.GetBool("nosendjoinpart") { | ||||
| 			return true | ||||
| 		} | ||||
| 		b.Log.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account) | ||||
| 		b.Remote <- config.Message{Username: "system", Text: message.Text, Channel: message.Channel, Account: b.Account, Event: config.EVENT_JOIN_LEAVE} | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	// Handle edited messages | ||||
| 	if (message.Raw.Event == "post_edited") && b.GetBool("EditDisable") { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	// Ignore messages sent from matterbridge | ||||
| 	if message.Post.Props != nil { | ||||
| 		if _, ok := message.Post.Props["matterbridge_"+b.uuid].(bool); ok { | ||||
| 			b.Log.Debugf("sent by matterbridge, ignoring") | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Ignore messages sent from a user logged in as the bot | ||||
| 	if b.mc.User.Username == message.Username { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	// if the message has reactions don't repost it (for now, until we can correlate reaction with message) | ||||
| 	if message.Post.HasReactions { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	// ignore messages from other teams than ours | ||||
| 	if message.Raw.Data["team_id"].(string) != b.TeamID { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	// only handle posted, edited or deleted events | ||||
| 	if !(message.Raw.Event == "posted" || message.Raw.Event == "post_edited" || message.Raw.Event == "post_deleted") { | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| package brocketchat | ||||
|  | ||||
| import ( | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	"github.com/42wim/matterbridge/hook/rockethook" | ||||
| 	"github.com/42wim/matterbridge/matterhook" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| type MMhook struct { | ||||
| @@ -14,18 +15,11 @@ type MMhook struct { | ||||
|  | ||||
| type Brocketchat struct { | ||||
| 	MMhook | ||||
| 	*config.BridgeConfig | ||||
| 	*bridge.Config | ||||
| } | ||||
|  | ||||
| var flog *log.Entry | ||||
| var protocol = "rocketchat" | ||||
|  | ||||
| func init() { | ||||
| 	flog = log.WithFields(log.Fields{"module": protocol}) | ||||
| } | ||||
|  | ||||
| func New(cfg *config.BridgeConfig) *Brocketchat { | ||||
| 	return &Brocketchat{BridgeConfig: cfg} | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	return &Brocketchat{Config: cfg} | ||||
| } | ||||
|  | ||||
| func (b *Brocketchat) Command(cmd string) string { | ||||
| @@ -33,11 +27,11 @@ func (b *Brocketchat) Command(cmd string) string { | ||||
| } | ||||
|  | ||||
| func (b *Brocketchat) Connect() error { | ||||
| 	flog.Info("Connecting webhooks") | ||||
| 	b.mh = matterhook.New(b.Config.WebhookURL, | ||||
| 		matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify, | ||||
| 	b.Log.Info("Connecting webhooks") | ||||
| 	b.mh = matterhook.New(b.GetString("WebhookURL"), | ||||
| 		matterhook.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), | ||||
| 			DisableServer: true}) | ||||
| 	b.rh = rockethook.New(b.Config.WebhookURL, rockethook.Config{BindAddress: b.Config.WebhookBindAddress}) | ||||
| 	b.rh = rockethook.New(b.GetString("WebhookURL"), rockethook.Config{BindAddress: b.GetString("WebhookBindAddress")}) | ||||
| 	go b.handleRocketHook() | ||||
| 	return nil | ||||
| } | ||||
| @@ -56,15 +50,32 @@ func (b *Brocketchat) Send(msg config.Message) (string, error) { | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL} | ||||
| 	b.Log.Debugf("=> Receiving %#v", msg) | ||||
| 	if msg.Extra != nil { | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			iconURL := config.GetIconURL(&rmsg, b.GetString("iconurl")) | ||||
| 			matterMessage := matterhook.OMessage{IconURL: iconURL, Channel: rmsg.Channel, UserName: rmsg.Username, Text: rmsg.Text} | ||||
| 			b.mh.Send(matterMessage) | ||||
| 		} | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			for _, f := range msg.Extra["file"] { | ||||
| 				fi := f.(config.FileInfo) | ||||
| 				if fi.URL != "" { | ||||
| 					msg.Text += fi.URL | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	iconURL := config.GetIconURL(&msg, b.GetString("iconurl")) | ||||
| 	matterMessage := matterhook.OMessage{IconURL: iconURL} | ||||
| 	matterMessage.Channel = msg.Channel | ||||
| 	matterMessage.UserName = msg.Username | ||||
| 	matterMessage.Type = "" | ||||
| 	matterMessage.Text = msg.Text | ||||
| 	err := b.mh.Send(matterMessage) | ||||
| 	if err != nil { | ||||
| 		flog.Info(err) | ||||
| 		b.Log.Info(err) | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return "", nil | ||||
| @@ -73,12 +84,12 @@ func (b *Brocketchat) Send(msg config.Message) (string, error) { | ||||
| func (b *Brocketchat) handleRocketHook() { | ||||
| 	for { | ||||
| 		message := b.rh.Receive() | ||||
| 		flog.Debugf("Receiving from rockethook %#v", message) | ||||
| 		b.Log.Debugf("Receiving from rockethook %#v", message) | ||||
| 		// do not loop | ||||
| 		if message.UserName == b.Config.Nick { | ||||
| 		if message.UserName == b.GetString("Nick") { | ||||
| 			continue | ||||
| 		} | ||||
| 		flog.Debugf("Sending message from %s on %s to gateway", message.UserName, b.Account) | ||||
| 		b.Log.Debugf("<= Sending message from %s on %s to gateway", message.UserName, b.Account) | ||||
| 		b.Remote <- config.Message{Text: message.Text, Username: message.UserName, Channel: message.ChannelName, Account: b.Account, UserID: message.UserID} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -4,46 +4,42 @@ import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/matterhook" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	"github.com/nlopes/slack" | ||||
| 	"html" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	"github.com/42wim/matterbridge/matterhook" | ||||
| 	"github.com/hashicorp/golang-lru" | ||||
| 	"github.com/nlopes/slack" | ||||
| 	"github.com/rs/xid" | ||||
| ) | ||||
|  | ||||
| type MMMessage struct { | ||||
| 	Text     string | ||||
| 	Channel  string | ||||
| 	Username string | ||||
| 	UserID   string | ||||
| 	Raw      *slack.MessageEvent | ||||
| } | ||||
|  | ||||
| type Bslack struct { | ||||
| 	mh       *matterhook.Client | ||||
| 	sc       *slack.Client | ||||
| 	rtm      *slack.RTM | ||||
| 	Plus     bool | ||||
| 	Users    []slack.User | ||||
| 	si       *slack.Info | ||||
| 	channels []slack.Channel | ||||
| 	*config.BridgeConfig | ||||
| 	mh           *matterhook.Client | ||||
| 	sc           *slack.Client | ||||
| 	rtm          *slack.RTM | ||||
| 	Users        []slack.User | ||||
| 	Usergroups   []slack.UserGroup | ||||
| 	si           *slack.Info | ||||
| 	channels     []slack.Channel | ||||
| 	cache        *lru.Cache | ||||
| 	UseChannelID bool | ||||
| 	uuid         string | ||||
| 	*bridge.Config | ||||
| 	sync.RWMutex | ||||
| } | ||||
|  | ||||
| var flog *log.Entry | ||||
| var protocol = "slack" | ||||
| const messageDeleted = "message_deleted" | ||||
|  | ||||
| func init() { | ||||
| 	flog = log.WithFields(log.Fields{"module": protocol}) | ||||
| } | ||||
|  | ||||
| func New(cfg *config.BridgeConfig) *Bslack { | ||||
| 	return &Bslack{BridgeConfig: cfg} | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	b := &Bslack{Config: cfg, uuid: xid.New().String()} | ||||
| 	b.cache, _ = lru.New(5000) | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| func (b *Bslack) Command(cmd string) string { | ||||
| @@ -51,71 +47,90 @@ func (b *Bslack) Command(cmd string) string { | ||||
| } | ||||
|  | ||||
| func (b *Bslack) Connect() error { | ||||
| 	if b.Config.WebhookBindAddress != "" { | ||||
| 		if b.Config.WebhookURL != "" { | ||||
| 			flog.Info("Connecting using webhookurl (sending) and webhookbindaddress (receiving)") | ||||
| 			b.mh = matterhook.New(b.Config.WebhookURL, | ||||
| 				matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify, | ||||
| 					BindAddress: b.Config.WebhookBindAddress}) | ||||
| 		} else if b.Config.Token != "" { | ||||
| 			flog.Info("Connecting using token (sending)") | ||||
| 			b.sc = slack.New(b.Config.Token) | ||||
| 	b.RLock() | ||||
| 	defer b.RUnlock() | ||||
| 	if b.GetString("WebhookBindAddress") != "" { | ||||
| 		if b.GetString("WebhookURL") != "" { | ||||
| 			b.Log.Info("Connecting using webhookurl (sending) and webhookbindaddress (receiving)") | ||||
| 			b.mh = matterhook.New(b.GetString("WebhookURL"), | ||||
| 				matterhook.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), | ||||
| 					BindAddress: b.GetString("WebhookBindAddress")}) | ||||
| 		} else if b.GetString("Token") != "" { | ||||
| 			b.Log.Info("Connecting using token (sending)") | ||||
| 			b.sc = slack.New(b.GetString("Token")) | ||||
| 			b.rtm = b.sc.NewRTM() | ||||
| 			go b.rtm.ManageConnection() | ||||
| 			flog.Info("Connecting using webhookbindaddress (receiving)") | ||||
| 			b.mh = matterhook.New(b.Config.WebhookURL, | ||||
| 				matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify, | ||||
| 					BindAddress: b.Config.WebhookBindAddress}) | ||||
| 			b.Log.Info("Connecting using webhookbindaddress (receiving)") | ||||
| 			b.mh = matterhook.New(b.GetString("WebhookURL"), | ||||
| 				matterhook.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), | ||||
| 					BindAddress: b.GetString("WebhookBindAddress")}) | ||||
| 		} else { | ||||
| 			flog.Info("Connecting using webhookbindaddress (receiving)") | ||||
| 			b.mh = matterhook.New(b.Config.WebhookURL, | ||||
| 				matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify, | ||||
| 					BindAddress: b.Config.WebhookBindAddress}) | ||||
| 			b.Log.Info("Connecting using webhookbindaddress (receiving)") | ||||
| 			b.mh = matterhook.New(b.GetString("WebhookURL"), | ||||
| 				matterhook.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), | ||||
| 					BindAddress: b.GetString("WebhookBindAddress")}) | ||||
| 		} | ||||
| 		go b.handleSlack() | ||||
| 		return nil | ||||
| 	} | ||||
| 	if b.Config.WebhookURL != "" { | ||||
| 		flog.Info("Connecting using webhookurl (sending)") | ||||
| 		b.mh = matterhook.New(b.Config.WebhookURL, | ||||
| 			matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify, | ||||
| 	if b.GetString("WebhookURL") != "" { | ||||
| 		b.Log.Info("Connecting using webhookurl (sending)") | ||||
| 		b.mh = matterhook.New(b.GetString("WebhookURL"), | ||||
| 			matterhook.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), | ||||
| 				DisableServer: true}) | ||||
| 		if b.Config.Token != "" { | ||||
| 			flog.Info("Connecting using token (receiving)") | ||||
| 			b.sc = slack.New(b.Config.Token) | ||||
| 		if b.GetString("Token") != "" { | ||||
| 			b.Log.Info("Connecting using token (receiving)") | ||||
| 			b.sc = slack.New(b.GetString("Token")) | ||||
| 			b.rtm = b.sc.NewRTM() | ||||
| 			go b.rtm.ManageConnection() | ||||
| 			go b.handleSlack() | ||||
| 		} | ||||
| 	} else if b.Config.Token != "" { | ||||
| 		flog.Info("Connecting using token (sending and receiving)") | ||||
| 		b.sc = slack.New(b.Config.Token) | ||||
| 	} else if b.GetString("Token") != "" { | ||||
| 		b.Log.Info("Connecting using token (sending and receiving)") | ||||
| 		b.sc = slack.New(b.GetString("Token")) | ||||
| 		b.rtm = b.sc.NewRTM() | ||||
| 		go b.rtm.ManageConnection() | ||||
| 		go b.handleSlack() | ||||
| 	} | ||||
| 	if b.Config.WebhookBindAddress == "" && b.Config.WebhookURL == "" && b.Config.Token == "" { | ||||
| 		return errors.New("No connection method found. See that you have WebhookBindAddress, WebhookURL or Token configured.") | ||||
| 	if b.GetString("WebhookBindAddress") == "" && b.GetString("WebhookURL") == "" && b.GetString("Token") == "" { | ||||
| 		return errors.New("no connection method found. See that you have WebhookBindAddress, WebhookURL or Token configured") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Bslack) Disconnect() error { | ||||
| 	return nil | ||||
|  | ||||
| 	return b.rtm.Disconnect() | ||||
| } | ||||
|  | ||||
| func (b *Bslack) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	// use ID:channelid and resolve it to the actual name | ||||
| 	idcheck := strings.Split(channel.Name, "ID:") | ||||
| 	if len(idcheck) > 1 { | ||||
| 		b.UseChannelID = true | ||||
| 		ch, err := b.sc.GetChannelInfo(idcheck[1]) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		channel.Name = ch.Name | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// we can only join channels using the API | ||||
| 	if b.sc != nil { | ||||
| 		if strings.HasPrefix(b.Config.Token, "xoxb") { | ||||
| 		if strings.HasPrefix(b.GetString("Token"), "xoxb") { | ||||
| 			// TODO check if bot has already joined channel | ||||
| 			return nil | ||||
| 		} | ||||
| 		_, err := b.sc.JoinChannel(channel.Name) | ||||
| 		if err != nil { | ||||
| 			if err.Error() != "name_taken" { | ||||
| 				return err | ||||
| 			switch err.Error() { | ||||
| 			case "name_taken", "restricted_action": | ||||
| 			case "default": | ||||
| 				{ | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -123,48 +138,21 @@ func (b *Bslack) JoinChannel(channel config.ChannelInfo) error { | ||||
| } | ||||
|  | ||||
| func (b *Bslack) Send(msg config.Message) (string, error) { | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	b.Log.Debugf("=> Receiving %#v", msg) | ||||
|  | ||||
| 	// Make a action /me of the message | ||||
| 	if msg.Event == config.EVENT_USER_ACTION { | ||||
| 		msg.Text = "_" + msg.Text + "_" | ||||
| 	} | ||||
| 	nick := msg.Username | ||||
| 	message := msg.Text | ||||
| 	channel := msg.Channel | ||||
| 	if b.Config.PrefixMessagesWithNick { | ||||
| 		message = nick + " " + message | ||||
| 	} | ||||
| 	if b.Config.WebhookURL != "" { | ||||
| 		matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL} | ||||
| 		matterMessage.Channel = channel | ||||
| 		matterMessage.UserName = nick | ||||
| 		matterMessage.Type = "" | ||||
| 		matterMessage.Text = message | ||||
| 		err := b.mh.Send(matterMessage) | ||||
| 		if err != nil { | ||||
| 			flog.Info(err) | ||||
| 			return "", err | ||||
| 		} | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	schannel, err := b.getChannelByName(channel) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	np := slack.NewPostMessageParameters() | ||||
| 	if b.Config.PrefixMessagesWithNick { | ||||
| 		np.AsUser = true | ||||
| 	} | ||||
| 	np.Username = nick | ||||
| 	np.IconURL = config.GetIconURL(&msg, &b.Config) | ||||
| 	if msg.Avatar != "" { | ||||
| 		np.IconURL = msg.Avatar | ||||
| 	} | ||||
| 	np.Attachments = append(np.Attachments, slack.Attachment{CallbackID: "matterbridge"}) | ||||
| 	np.Attachments = append(np.Attachments, b.createAttach(msg.Extra)...) | ||||
|  | ||||
| 	// replace mentions | ||||
| 	np.LinkNames = 1 | ||||
| 	// Use webhook to send the message | ||||
| 	if b.GetString("WebhookURL") != "" { | ||||
| 		return b.sendWebhook(msg) | ||||
| 	} | ||||
|  | ||||
| 	channelID := b.getChannelID(msg.Channel) | ||||
|  | ||||
| 	// Delete message | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		// some protocols echo deletes, but with empty ID | ||||
| 		if msg.ID == "" { | ||||
| @@ -172,47 +160,78 @@ func (b *Bslack) Send(msg config.Message) (string, error) { | ||||
| 		} | ||||
| 		// we get a "slack <ID>", split it | ||||
| 		ts := strings.Fields(msg.ID) | ||||
| 		b.sc.DeleteMessage(schannel.ID, ts[1]) | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	// if we have no ID it means we're creating a new message, not updating an existing one | ||||
| 	if msg.ID != "" { | ||||
| 		ts := strings.Fields(msg.ID) | ||||
| 		b.sc.UpdateMessage(schannel.ID, ts[1], message) | ||||
| 		return "", nil | ||||
| 		_, _, err := b.sc.DeleteMessage(channelID, ts[1]) | ||||
| 		if err != nil { | ||||
| 			return msg.ID, err | ||||
| 		} | ||||
| 		return msg.ID, nil | ||||
| 	} | ||||
|  | ||||
| 	if msg.Extra != nil { | ||||
| 		// check if we have files to upload (from slack, telegram or mattermost) | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			var err error | ||||
| 			for _, f := range msg.Extra["file"] { | ||||
| 				fi := f.(config.FileInfo) | ||||
| 				_, err = b.sc.UploadFile(slack.FileUploadParameters{ | ||||
| 					Reader:         bytes.NewReader(*fi.Data), | ||||
| 					Filename:       fi.Name, | ||||
| 					Channels:       []string{schannel.ID}, | ||||
| 					InitialComment: fi.Comment, | ||||
| 				}) | ||||
| 				if err != nil { | ||||
| 					flog.Errorf("uploadfile %#v", err) | ||||
| 				} | ||||
| 			} | ||||
| 	// Prepend nick if configured | ||||
| 	if b.GetBool("PrefixMessagesWithNick") { | ||||
| 		msg.Text = msg.Username + msg.Text | ||||
| 	} | ||||
|  | ||||
| 	// Edit message if we have an ID | ||||
| 	if msg.ID != "" { | ||||
| 		ts := strings.Fields(msg.ID) | ||||
| 		_, _, _, err := b.sc.UpdateMessage(channelID, ts[1], msg.Text) | ||||
| 		if err != nil { | ||||
| 			return msg.ID, err | ||||
| 		} | ||||
| 		return msg.ID, nil | ||||
| 	} | ||||
|  | ||||
| 	// create slack new post parameters | ||||
| 	np := slack.NewPostMessageParameters() | ||||
| 	if b.GetBool("PrefixMessagesWithNick") { | ||||
| 		np.AsUser = true | ||||
| 	} | ||||
| 	np.Username = msg.Username | ||||
| 	np.LinkNames = 1 // replace mentions | ||||
| 	np.IconURL = config.GetIconURL(&msg, b.GetString("iconurl")) | ||||
| 	if msg.Avatar != "" { | ||||
| 		np.IconURL = msg.Avatar | ||||
| 	} | ||||
| 	// add a callback ID so we can see we created it | ||||
| 	np.Attachments = append(np.Attachments, slack.Attachment{CallbackID: "matterbridge_" + b.uuid}) | ||||
| 	// add file attachments | ||||
| 	np.Attachments = append(np.Attachments, b.createAttach(msg.Extra)...) | ||||
| 	// add slack attachments (from another slack bridge) | ||||
| 	if len(msg.Extra["slack_attachment"]) > 0 { | ||||
| 		for _, attach := range msg.Extra["slack_attachment"] { | ||||
| 			np.Attachments = append(np.Attachments, attach.([]slack.Attachment)...) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	_, id, err := b.sc.PostMessage(schannel.ID, message, np) | ||||
| 	// Upload a file if it exists | ||||
| 	if msg.Extra != nil { | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			b.sc.PostMessage(channelID, rmsg.Username+rmsg.Text, np) | ||||
| 		} | ||||
| 		// check if we have files to upload (from slack, telegram or mattermost) | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			b.handleUploadFile(&msg, channelID) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Post normal message | ||||
| 	_, id, err := b.sc.PostMessage(channelID, msg.Text, np) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return "slack " + id, nil | ||||
| } | ||||
|  | ||||
| func (b *Bslack) getAvatar(user string) string { | ||||
| func (b *Bslack) Reload(cfg *bridge.Config) (string, error) { | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| func (b *Bslack) getAvatar(userid string) string { | ||||
| 	var avatar string | ||||
| 	if b.Users != nil { | ||||
| 		for _, u := range b.Users { | ||||
| 			if user == u.Name { | ||||
| 			if userid == u.ID { | ||||
| 				return u.Profile.Image48 | ||||
| 			} | ||||
| 		} | ||||
| @@ -220,6 +239,7 @@ func (b *Bslack) getAvatar(user string) string { | ||||
| 	return avatar | ||||
| } | ||||
|  | ||||
| /* | ||||
| func (b *Bslack) getChannelByName(name string) (*slack.Channel, error) { | ||||
| 	if b.channels == nil { | ||||
| 		return nil, fmt.Errorf("%s: channel %s not found (no channels found)", b.Account, name) | ||||
| @@ -231,6 +251,7 @@ func (b *Bslack) getChannelByName(name string) (*slack.Channel, error) { | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("%s: channel %s not found", b.Account, name) | ||||
| } | ||||
| */ | ||||
|  | ||||
| func (b *Bslack) getChannelByID(ID string) (*slack.Channel, error) { | ||||
| 	if b.channels == nil { | ||||
| @@ -245,179 +266,82 @@ func (b *Bslack) getChannelByID(ID string) (*slack.Channel, error) { | ||||
| } | ||||
|  | ||||
| func (b *Bslack) handleSlack() { | ||||
| 	mchan := make(chan *MMMessage) | ||||
| 	if b.Config.WebhookBindAddress != "" { | ||||
| 		flog.Debugf("Choosing webhooks based receiving") | ||||
| 		go b.handleMatterHook(mchan) | ||||
| 	messages := make(chan *config.Message) | ||||
| 	if b.GetString("WebhookBindAddress") != "" { | ||||
| 		b.Log.Debugf("Choosing webhooks based receiving") | ||||
| 		go b.handleMatterHook(messages) | ||||
| 	} else { | ||||
| 		flog.Debugf("Choosing token based receiving") | ||||
| 		go b.handleSlackClient(mchan) | ||||
| 		b.Log.Debugf("Choosing token based receiving") | ||||
| 		go b.handleSlackClient(messages) | ||||
| 	} | ||||
| 	time.Sleep(time.Second) | ||||
| 	flog.Debug("Start listening for Slack messages") | ||||
| 	for message := range mchan { | ||||
| 		// do not send messages from ourself | ||||
| 		if b.Config.WebhookURL == "" && b.Config.WebhookBindAddress == "" && message.Username == b.si.User.Name { | ||||
| 			continue | ||||
| 		} | ||||
| 		if (message.Text == "" || message.Username == "") && message.Raw.SubType != "message_deleted" { | ||||
| 			continue | ||||
| 		} | ||||
| 		text := message.Text | ||||
| 		text = b.replaceURL(text) | ||||
| 		text = html.UnescapeString(text) | ||||
| 		flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account) | ||||
| 		msg := config.Message{Text: text, Username: message.Username, Channel: message.Channel, Account: b.Account, Avatar: b.getAvatar(message.Username), UserID: message.UserID, ID: "slack " + message.Raw.Timestamp, Extra: make(map[string][]interface{})} | ||||
| 		if message.Raw.SubType == "me_message" { | ||||
| 			msg.Event = config.EVENT_USER_ACTION | ||||
| 		} | ||||
| 		if message.Raw.SubType == "channel_leave" || message.Raw.SubType == "channel_join" { | ||||
| 			msg.Username = "system" | ||||
| 			msg.Event = config.EVENT_JOIN_LEAVE | ||||
| 		} | ||||
| 		// edited messages have a submessage, use this timestamp | ||||
| 		if message.Raw.SubMessage != nil { | ||||
| 			msg.ID = "slack " + message.Raw.SubMessage.Timestamp | ||||
| 		} | ||||
| 		if message.Raw.SubType == "message_deleted" { | ||||
| 			msg.Text = config.EVENT_MSG_DELETE | ||||
| 			msg.Event = config.EVENT_MSG_DELETE | ||||
| 			msg.ID = "slack " + message.Raw.DeletedTimestamp | ||||
| 		} | ||||
| 	b.Log.Debug("Start listening for Slack messages") | ||||
| 	for message := range messages { | ||||
| 		b.Log.Debugf("<= Sending message from %s on %s to gateway", message.Username, b.Account) | ||||
|  | ||||
| 		// if we have a file attached, download it (in memory) and put a pointer to it in msg.Extra | ||||
| 		if message.Raw.File != nil { | ||||
| 			// limit to 1MB for now | ||||
| 			if message.Raw.File.Size <= b.General.MediaDownloadSize { | ||||
| 				comment := "" | ||||
| 				data, err := b.downloadFile(message.Raw.File.URLPrivateDownload) | ||||
| 				if err != nil { | ||||
| 					flog.Errorf("download %s failed %#v", message.Raw.File.URLPrivateDownload, err) | ||||
| 				} else { | ||||
| 					results := regexp.MustCompile(`.*?commented: (.*)`).FindAllStringSubmatch(msg.Text, -1) | ||||
| 					if len(results) > 0 { | ||||
| 						comment = results[0][1] | ||||
| 					} | ||||
| 					msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{Name: message.Raw.File.Name, Data: data, Comment: comment}) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		flog.Debugf("Message is %#v", msg) | ||||
| 		b.Remote <- msg | ||||
| 		// cleanup the message | ||||
| 		message.Text = b.replaceMention(message.Text) | ||||
| 		message.Text = b.replaceVariable(message.Text) | ||||
| 		message.Text = b.replaceChannel(message.Text) | ||||
| 		message.Text = b.replaceURL(message.Text) | ||||
| 		message.Text = html.UnescapeString(message.Text) | ||||
|  | ||||
| 		// Add the avatar | ||||
| 		message.Avatar = b.getAvatar(message.UserID) | ||||
|  | ||||
| 		b.Log.Debugf("<= Message is %#v", message) | ||||
| 		b.Remote <- *message | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Bslack) handleSlackClient(mchan chan *MMMessage) { | ||||
| func (b *Bslack) handleSlackClient(messages chan *config.Message) { | ||||
| 	for msg := range b.rtm.IncomingEvents { | ||||
| 		if msg.Type != "user_typing" && msg.Type != "latency_report" { | ||||
| 			flog.Debugf("Receiving from slackclient %#v", msg.Data) | ||||
| 			b.Log.Debugf("== Receiving event %#v", msg.Data) | ||||
| 		} | ||||
| 		switch ev := msg.Data.(type) { | ||||
| 		case *slack.MessageEvent: | ||||
| 			if len(ev.Attachments) > 0 { | ||||
| 				// skip messages we made ourselves | ||||
| 				if ev.Attachments[0].CallbackID == "matterbridge" { | ||||
| 					continue | ||||
| 				} | ||||
| 			} | ||||
| 			if !b.Config.EditDisable && ev.SubMessage != nil && ev.SubMessage.ThreadTimestamp != ev.SubMessage.Timestamp { | ||||
| 				flog.Debugf("SubMessage %#v", ev.SubMessage) | ||||
| 				ev.User = ev.SubMessage.User | ||||
| 				ev.Text = ev.SubMessage.Text + b.Config.EditSuffix | ||||
|  | ||||
| 				// it seems ev.SubMessage.Edited == nil when slack unfurls | ||||
| 				// do not forward these messages #266 | ||||
| 				if ev.SubMessage.Edited == nil { | ||||
| 					continue | ||||
| 				} | ||||
| 			} | ||||
| 			// use our own func because rtm.GetChannelInfo doesn't work for private channels | ||||
| 			channel, err := b.getChannelByID(ev.Channel) | ||||
| 			if err != nil { | ||||
| 			if b.skipMessageEvent(ev) { | ||||
| 				b.Log.Debugf("Skipped message: %#v", ev) | ||||
| 				continue | ||||
| 			} | ||||
| 			m := &MMMessage{} | ||||
| 			if ev.BotID == "" && ev.SubType != "message_deleted" { | ||||
| 				user, err := b.rtm.GetUserInfo(ev.User) | ||||
| 				if err != nil { | ||||
| 					continue | ||||
| 				} | ||||
| 				m.UserID = user.ID | ||||
| 				m.Username = user.Name | ||||
| 				if user.Profile.DisplayName != "" { | ||||
| 					m.Username = user.Profile.DisplayName | ||||
| 				} | ||||
| 			rmsg, err := b.handleMessageEvent(ev) | ||||
| 			if err != nil { | ||||
| 				b.Log.Errorf("%#v", err) | ||||
| 				continue | ||||
| 			} | ||||
| 			m.Channel = channel.Name | ||||
| 			m.Text = ev.Text | ||||
| 			if m.Text == "" { | ||||
| 				for _, attach := range ev.Attachments { | ||||
| 					if attach.Text != "" { | ||||
| 						m.Text = attach.Text | ||||
| 					} else { | ||||
| 						m.Text = attach.Fallback | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			m.Raw = ev | ||||
| 			m.Text = b.replaceMention(m.Text) | ||||
| 			m.Text = b.replaceVariable(m.Text) | ||||
| 			m.Text = b.replaceChannel(m.Text) | ||||
| 			// when using webhookURL we can't check if it's our webhook or not for now | ||||
| 			if ev.BotID != "" && b.Config.WebhookURL == "" { | ||||
| 				bot, err := b.rtm.GetBotInfo(ev.BotID) | ||||
| 				if err != nil { | ||||
| 					continue | ||||
| 				} | ||||
| 				if bot.Name != "" { | ||||
| 					m.Username = bot.Name | ||||
| 					if ev.Username != "" { | ||||
| 						m.Username = ev.Username | ||||
| 					} | ||||
| 					m.UserID = bot.ID | ||||
| 				} | ||||
| 			} | ||||
| 			mchan <- m | ||||
| 			messages <- rmsg | ||||
| 		case *slack.OutgoingErrorEvent: | ||||
| 			flog.Debugf("%#v", ev.Error()) | ||||
| 			b.Log.Debugf("%#v", ev.Error()) | ||||
| 		case *slack.ChannelJoinedEvent: | ||||
| 			b.Users, _ = b.sc.GetUsers() | ||||
| 			b.Usergroups, _ = b.sc.GetUserGroups() | ||||
| 		case *slack.ConnectedEvent: | ||||
| 			b.channels = ev.Info.Channels | ||||
| 			var err error | ||||
| 			b.channels, _, err = b.sc.GetConversations(&slack.GetConversationsParameters{}) | ||||
| 			if err != nil { | ||||
| 				b.Log.Errorf("Channel list failed: %#v", err) | ||||
| 			} | ||||
| 			b.si = ev.Info | ||||
| 			b.Users, _ = b.sc.GetUsers() | ||||
| 			// add private channels | ||||
| 			groups, _ := b.sc.GetGroups(true) | ||||
| 			for _, g := range groups { | ||||
| 				channel := new(slack.Channel) | ||||
| 				channel.ID = g.ID | ||||
| 				channel.Name = g.Name | ||||
| 				b.channels = append(b.channels, *channel) | ||||
| 			} | ||||
| 			b.Usergroups, _ = b.sc.GetUserGroups() | ||||
| 		case *slack.InvalidAuthEvent: | ||||
| 			flog.Fatalf("Invalid Token %#v", ev) | ||||
| 			b.Log.Fatalf("Invalid Token %#v", ev) | ||||
| 		case *slack.ConnectionErrorEvent: | ||||
| 			flog.Errorf("Connection failed %#v %#v", ev.Error(), ev.ErrorObj) | ||||
| 			b.Log.Errorf("Connection failed %#v %#v", ev.Error(), ev.ErrorObj) | ||||
| 		default: | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Bslack) handleMatterHook(mchan chan *MMMessage) { | ||||
| func (b *Bslack) handleMatterHook(messages chan *config.Message) { | ||||
| 	for { | ||||
| 		message := b.mh.Receive() | ||||
| 		flog.Debugf("receiving from matterhook (slack) %#v", message) | ||||
| 		m := &MMMessage{} | ||||
| 		m.Username = message.UserName | ||||
| 		m.Text = message.Text | ||||
| 		m.Text = b.replaceMention(m.Text) | ||||
| 		m.Text = b.replaceVariable(m.Text) | ||||
| 		m.Text = b.replaceChannel(m.Text) | ||||
| 		m.Channel = message.ChannelName | ||||
| 		if m.Username == "slackbot" { | ||||
| 		b.Log.Debugf("receiving from matterhook (slack) %#v", message) | ||||
| 		if message.UserName == "slackbot" { | ||||
| 			continue | ||||
| 		} | ||||
| 		mchan <- m | ||||
| 		messages <- &config.Message{Username: message.UserName, Text: message.Text, Channel: message.ChannelName} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -433,9 +357,20 @@ func (b *Bslack) userName(id string) string { | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| /* | ||||
| func (b *Bslack) userGroupName(id string) string { | ||||
| 	for _, u := range b.Usergroups { | ||||
| 		if u.ID == id { | ||||
| 			return u.Name | ||||
| 		} | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
| */ | ||||
|  | ||||
| // @see https://api.slack.com/docs/message-formatting#linking_to_channels_and_users | ||||
| func (b *Bslack) replaceMention(text string) string { | ||||
| 	results := regexp.MustCompile(`<@([a-zA-z0-9]+)>`).FindAllStringSubmatch(text, -1) | ||||
| 	results := regexp.MustCompile(`<@([a-zA-Z0-9]+)>`).FindAllStringSubmatch(text, -1) | ||||
| 	for _, r := range results { | ||||
| 		text = strings.Replace(text, "<@"+r[1]+">", "@"+b.userName(r[1]), -1) | ||||
| 	} | ||||
| @@ -453,9 +388,13 @@ func (b *Bslack) replaceChannel(text string) string { | ||||
|  | ||||
| // @see https://api.slack.com/docs/message-formatting#variables | ||||
| func (b *Bslack) replaceVariable(text string) string { | ||||
| 	results := regexp.MustCompile(`<!([a-zA-Z0-9]+)(\|.+?)?>`).FindAllStringSubmatch(text, -1) | ||||
| 	results := regexp.MustCompile(`<!((?:subteam\^)?[a-zA-Z0-9]+)(?:\|@?(.+?))?>`).FindAllStringSubmatch(text, -1) | ||||
| 	for _, r := range results { | ||||
| 		text = strings.Replace(text, r[0], "@"+r[1], -1) | ||||
| 		if r[2] != "" { | ||||
| 			text = strings.Replace(text, r[0], "@"+r[2], -1) | ||||
| 		} else { | ||||
| 			text = strings.Replace(text, r[0], "@"+r[1], -1) | ||||
| 		} | ||||
| 	} | ||||
| 	return text | ||||
| } | ||||
| @@ -464,7 +403,11 @@ func (b *Bslack) replaceVariable(text string) string { | ||||
| func (b *Bslack) replaceURL(text string) string { | ||||
| 	results := regexp.MustCompile(`<(.*?)(\|.*?)?>`).FindAllStringSubmatch(text, -1) | ||||
| 	for _, r := range results { | ||||
| 		text = strings.Replace(text, r[0], r[1], -1) | ||||
| 		if len(strings.TrimSpace(r[2])) == 1 { // A display text separator was found, but the text was blank | ||||
| 			text = strings.Replace(text, r[0], "", -1) | ||||
| 		} else { | ||||
| 			text = strings.Replace(text, r[0], r[1], -1) | ||||
| 		} | ||||
| 	} | ||||
| 	return text | ||||
| } | ||||
| @@ -492,23 +435,310 @@ func (b *Bslack) createAttach(extra map[string][]interface{}) []slack.Attachment | ||||
| 	return attachs | ||||
| } | ||||
|  | ||||
| func (b *Bslack) downloadFile(url string) (*[]byte, error) { | ||||
| 	var buf bytes.Buffer | ||||
| 	client := &http.Client{ | ||||
| 		Timeout: time.Second * 5, | ||||
| // handleDownloadFile handles file download | ||||
| func (b *Bslack) handleDownloadFile(rmsg *config.Message, file *slack.File) error { | ||||
| 	// if we have a file attached, download it (in memory) and put a pointer to it in msg.Extra | ||||
| 	// limit to 1MB for now | ||||
| 	comment := "" | ||||
| 	results := regexp.MustCompile(`.*?commented: (.*)`).FindAllStringSubmatch(rmsg.Text, -1) | ||||
| 	if len(results) > 0 { | ||||
| 		comment = results[0][1] | ||||
| 	} | ||||
| 	req, err := http.NewRequest("GET", url, nil) | ||||
| 	err := helper.HandleDownloadSize(b.Log, rmsg, file.Name, int64(file.Size), b.General) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 		return err | ||||
| 	} | ||||
| 	req.Header.Add("Authorization", "Bearer "+b.Config.Token) | ||||
| 	resp, err := client.Do(req) | ||||
| 	// actually download the file | ||||
| 	data, err := helper.DownloadFileAuth(file.URLPrivateDownload, "Bearer "+b.GetString("Token")) | ||||
| 	if err != nil { | ||||
| 		resp.Body.Close() | ||||
| 		return nil, err | ||||
| 		return fmt.Errorf("download %s failed %#v", file.URLPrivateDownload, err) | ||||
| 	} | ||||
| 	io.Copy(&buf, resp.Body) | ||||
| 	data := buf.Bytes() | ||||
| 	resp.Body.Close() | ||||
| 	return &data, nil | ||||
| 	// add the downloaded data to the message | ||||
| 	helper.HandleDownloadData(b.Log, rmsg, file.Name, comment, file.URLPrivateDownload, data, b.General) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // handleUploadFile handles native upload of files | ||||
| func (b *Bslack) handleUploadFile(msg *config.Message, channelID string) (string, error) { | ||||
| 	for _, f := range msg.Extra["file"] { | ||||
| 		fi := f.(config.FileInfo) | ||||
| 		if msg.Text == fi.Comment { | ||||
| 			msg.Text = "" | ||||
| 		} | ||||
| 		/* because the result of the UploadFile is slower than the MessageEvent from slack | ||||
| 		we can't match on the file ID yet, so we have to match on the filename too | ||||
| 		*/ | ||||
| 		b.Log.Debugf("Adding file %s to cache %s", fi.Name, time.Now().String()) | ||||
| 		b.cache.Add("filename"+fi.Name, time.Now()) | ||||
| 		res, err := b.sc.UploadFile(slack.FileUploadParameters{ | ||||
| 			Reader:         bytes.NewReader(*fi.Data), | ||||
| 			Filename:       fi.Name, | ||||
| 			Channels:       []string{channelID}, | ||||
| 			InitialComment: fi.Comment, | ||||
| 		}) | ||||
| 		if res.ID != "" { | ||||
| 			b.Log.Debugf("Adding fileid %s to cache %s", res.ID, time.Now().String()) | ||||
| 			b.cache.Add("file"+res.ID, time.Now()) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			b.Log.Errorf("uploadfile %#v", err) | ||||
| 		} | ||||
| 	} | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| // handleMessageEvent handles the message events | ||||
| func (b *Bslack) handleMessageEvent(ev *slack.MessageEvent) (*config.Message, error) { | ||||
| 	// update the userlist on a channel_join | ||||
| 	if ev.SubType == "channel_join" { | ||||
| 		b.Users, _ = b.sc.GetUsers() | ||||
| 	} | ||||
|  | ||||
| 	// Edit message | ||||
| 	if !b.GetBool("EditDisable") && ev.SubMessage != nil && ev.SubMessage.ThreadTimestamp != ev.SubMessage.Timestamp { | ||||
| 		b.Log.Debugf("SubMessage %#v", ev.SubMessage) | ||||
| 		ev.User = ev.SubMessage.User | ||||
| 		ev.Text = ev.SubMessage.Text + b.GetString("EditSuffix") | ||||
| 	} | ||||
|  | ||||
| 	// use our own func because rtm.GetChannelInfo doesn't work for private channels | ||||
| 	channel, err := b.getChannelByID(ev.Channel) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	rmsg := config.Message{Text: ev.Text, Channel: channel.Name, Account: b.Account, ID: "slack " + ev.Timestamp, Extra: make(map[string][]interface{})} | ||||
|  | ||||
| 	if b.UseChannelID { | ||||
| 		rmsg.Channel = "ID:" + channel.ID | ||||
| 	} | ||||
|  | ||||
| 	// find the user id and name | ||||
| 	if ev.User != "" && ev.SubType != messageDeleted && ev.SubType != "file_comment" { | ||||
| 		user, err := b.rtm.GetUserInfo(ev.User) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		rmsg.UserID = user.ID | ||||
| 		rmsg.Username = user.Name | ||||
| 		if user.Profile.DisplayName != "" { | ||||
| 			rmsg.Username = user.Profile.DisplayName | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// See if we have some text in the attachments | ||||
| 	if rmsg.Text == "" { | ||||
| 		for _, attach := range ev.Attachments { | ||||
| 			if attach.Text != "" { | ||||
| 				if attach.Title != "" { | ||||
| 					rmsg.Text = attach.Title + "\n" | ||||
| 				} | ||||
| 				rmsg.Text += attach.Text | ||||
| 			} else { | ||||
| 				rmsg.Text = attach.Fallback | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// when using webhookURL we can't check if it's our webhook or not for now | ||||
| 	if rmsg.Username == "" && ev.BotID != "" && b.GetString("WebhookURL") == "" { | ||||
| 		bot, err := b.rtm.GetBotInfo(ev.BotID) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if bot.Name != "" { | ||||
| 			rmsg.Username = bot.Name | ||||
| 			if ev.Username != "" { | ||||
| 				rmsg.Username = ev.Username | ||||
| 			} | ||||
| 			rmsg.UserID = bot.ID | ||||
| 		} | ||||
|  | ||||
| 		// fixes issues with matterircd users | ||||
| 		if bot.Name == "Slack API Tester" { | ||||
| 			user, err := b.rtm.GetUserInfo(ev.User) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			rmsg.UserID = user.ID | ||||
| 			rmsg.Username = user.Name | ||||
| 			if user.Profile.DisplayName != "" { | ||||
| 				rmsg.Username = user.Profile.DisplayName | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// file comments are set by the system (because there is no username given) | ||||
| 	if ev.SubType == "file_comment" { | ||||
| 		rmsg.Username = "system" | ||||
| 	} | ||||
|  | ||||
| 	// do we have a /me action | ||||
| 	if ev.SubType == "me_message" { | ||||
| 		rmsg.Event = config.EVENT_USER_ACTION | ||||
| 	} | ||||
|  | ||||
| 	// Handle join/leave | ||||
| 	if ev.SubType == "channel_leave" || ev.SubType == "channel_join" { | ||||
| 		rmsg.Username = "system" | ||||
| 		rmsg.Event = config.EVENT_JOIN_LEAVE | ||||
| 	} | ||||
|  | ||||
| 	// edited messages have a submessage, use this timestamp | ||||
| 	if ev.SubMessage != nil { | ||||
| 		rmsg.ID = "slack " + ev.SubMessage.Timestamp | ||||
| 	} | ||||
|  | ||||
| 	// deleted message event | ||||
| 	if ev.SubType == messageDeleted { | ||||
| 		rmsg.Text = config.EVENT_MSG_DELETE | ||||
| 		rmsg.Event = config.EVENT_MSG_DELETE | ||||
| 		rmsg.ID = "slack " + ev.DeletedTimestamp | ||||
| 	} | ||||
|  | ||||
| 	// topic change event | ||||
| 	if ev.SubType == "channel_topic" || ev.SubType == "channel_purpose" { | ||||
| 		rmsg.Event = config.EVENT_TOPIC_CHANGE | ||||
| 	} | ||||
|  | ||||
| 	// Only deleted messages can have a empty username and text | ||||
| 	if (rmsg.Text == "" || rmsg.Username == "") && ev.SubType != messageDeleted && len(ev.Files) == 0 { | ||||
| 		// this is probably a webhook we couldn't resolve | ||||
| 		if ev.BotID != "" { | ||||
| 			return nil, fmt.Errorf("probably an incoming webhook we couldn't resolve (maybe ourselves)") | ||||
| 		} | ||||
| 		return nil, fmt.Errorf("empty message and not a deleted message") | ||||
| 	} | ||||
|  | ||||
| 	// save the attachments, so that we can send them to other slack (compatible) bridges | ||||
| 	if len(ev.Attachments) > 0 { | ||||
| 		rmsg.Extra["slack_attachment"] = append(rmsg.Extra["slack_attachment"], ev.Attachments) | ||||
| 	} | ||||
|  | ||||
| 	// if we have a file attached, download it (in memory) and put a pointer to it in msg.Extra | ||||
| 	if len(ev.Files) > 0 { | ||||
| 		for _, f := range ev.Files { | ||||
| 			err := b.handleDownloadFile(&rmsg, &f) | ||||
| 			if err != nil { | ||||
| 				b.Log.Errorf("download failed: %s", err) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return &rmsg, nil | ||||
| } | ||||
|  | ||||
| // sendWebhook uses the configured WebhookURL to send the message | ||||
| func (b *Bslack) sendWebhook(msg config.Message) (string, error) { | ||||
| 	// skip events | ||||
| 	if msg.Event != "" { | ||||
| 		return "", nil | ||||
| 	} | ||||
|  | ||||
| 	if b.GetBool("PrefixMessagesWithNick") { | ||||
| 		msg.Text = msg.Username + msg.Text | ||||
| 	} | ||||
|  | ||||
| 	if msg.Extra != nil { | ||||
| 		// this sends a message only if we received a config.EVENT_FILE_FAILURE_SIZE | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			iconURL := config.GetIconURL(&rmsg, b.GetString("iconurl")) | ||||
| 			matterMessage := matterhook.OMessage{IconURL: iconURL, Channel: msg.Channel, UserName: rmsg.Username, Text: rmsg.Text} | ||||
| 			b.mh.Send(matterMessage) | ||||
| 		} | ||||
|  | ||||
| 		// webhook doesn't support file uploads, so we add the url manually | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			for _, f := range msg.Extra["file"] { | ||||
| 				fi := f.(config.FileInfo) | ||||
| 				if fi.URL != "" { | ||||
| 					msg.Text += " " + fi.URL | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// if we have native slack_attachments add them | ||||
| 	var attachs []slack.Attachment | ||||
| 	if len(msg.Extra["slack_attachment"]) > 0 { | ||||
| 		for _, attach := range msg.Extra["slack_attachment"] { | ||||
| 			attachs = append(attachs, attach.([]slack.Attachment)...) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	iconURL := config.GetIconURL(&msg, b.GetString("iconurl")) | ||||
| 	matterMessage := matterhook.OMessage{IconURL: iconURL, Attachments: attachs, Channel: msg.Channel, UserName: msg.Username, Text: msg.Text} | ||||
| 	if msg.Avatar != "" { | ||||
| 		matterMessage.IconURL = msg.Avatar | ||||
| 	} | ||||
| 	err := b.mh.Send(matterMessage) | ||||
| 	if err != nil { | ||||
| 		b.Log.Error(err) | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| // skipMessageEvent skips event that need to be skipped :-) | ||||
| func (b *Bslack) skipMessageEvent(ev *slack.MessageEvent) bool { | ||||
| 	if ev.SubType == "channel_leave" || ev.SubType == "channel_join" { | ||||
| 		return b.GetBool("nosendjoinpart") | ||||
| 	} | ||||
|  | ||||
| 	// ignore pinned items | ||||
| 	if ev.SubType == "pinned_item" || ev.SubType == "unpinned_item" { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	// do not send messages from ourself | ||||
| 	if b.GetString("WebhookURL") == "" && b.GetString("WebhookBindAddress") == "" && ev.Username == b.si.User.Name { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	// skip messages we made ourselves | ||||
| 	if len(ev.Attachments) > 0 { | ||||
| 		if ev.Attachments[0].CallbackID == "matterbridge_"+b.uuid { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if !b.GetBool("EditDisable") && ev.SubMessage != nil && ev.SubMessage.ThreadTimestamp != ev.SubMessage.Timestamp { | ||||
| 		// it seems ev.SubMessage.Edited == nil when slack unfurls | ||||
| 		// do not forward these messages #266 | ||||
| 		if ev.SubMessage.Edited == nil { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(ev.Files) > 0 { | ||||
| 		for _, f := range ev.Files { | ||||
| 			// if the file is in the cache and isn't older then a minute, skip it | ||||
| 			if ts, ok := b.cache.Get("file" + f.ID); ok && time.Since(ts.(time.Time)) < time.Minute { | ||||
| 				b.Log.Debugf("Not downloading file id %s which we uploaded", f.ID) | ||||
| 				return true | ||||
| 			} else { | ||||
| 				if ts, ok := b.cache.Get("filename" + f.Name); ok && time.Since(ts.(time.Time)) < time.Second*10 { | ||||
| 					b.Log.Debugf("Not downloading file name %s which we uploaded", f.Name) | ||||
| 					return true | ||||
| 				} else { | ||||
| 					b.Log.Debugf("Not skipping %s %s", f.Name, time.Now().String()) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (b *Bslack) getChannelID(name string) string { | ||||
| 	idcheck := strings.Split(name, "ID:") | ||||
| 	if len(idcheck) > 1 { | ||||
| 		return idcheck[1] | ||||
| 	} | ||||
| 	for _, channel := range b.channels { | ||||
| 		if channel.Name == name { | ||||
| 			return channel.ID | ||||
| 		} | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|   | ||||
| @@ -2,35 +2,31 @@ package bsshchat | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	"github.com/shazow/ssh-chat/sshd" | ||||
| 	"io" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	"github.com/shazow/ssh-chat/sshd" | ||||
| 	log "github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| type Bsshchat struct { | ||||
| 	r *bufio.Scanner | ||||
| 	w io.WriteCloser | ||||
| 	*config.BridgeConfig | ||||
| 	*bridge.Config | ||||
| } | ||||
|  | ||||
| var flog *log.Entry | ||||
| var protocol = "sshchat" | ||||
|  | ||||
| func init() { | ||||
| 	flog = log.WithFields(log.Fields{"module": protocol}) | ||||
| } | ||||
|  | ||||
| func New(cfg *config.BridgeConfig) *Bsshchat { | ||||
| 	return &Bsshchat{BridgeConfig: cfg} | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	return &Bsshchat{Config: cfg} | ||||
| } | ||||
|  | ||||
| func (b *Bsshchat) Connect() error { | ||||
| 	var err error | ||||
| 	flog.Infof("Connecting %s", b.Config.Server) | ||||
| 	b.Log.Infof("Connecting %s", b.GetString("Server")) | ||||
| 	go func() { | ||||
| 		err = sshd.ConnectShell(b.Config.Server, b.Config.Nick, func(r io.Reader, w io.WriteCloser) error { | ||||
| 		err = sshd.ConnectShell(b.GetString("Server"), b.GetString("Nick"), func(r io.Reader, w io.WriteCloser) error { | ||||
| 			b.r = bufio.NewScanner(r) | ||||
| 			b.w = w | ||||
| 			b.r.Scan() | ||||
| @@ -40,10 +36,10 @@ func (b *Bsshchat) Connect() error { | ||||
| 		}) | ||||
| 	}() | ||||
| 	if err != nil { | ||||
| 		flog.Debugf("%#v", err) | ||||
| 		b.Log.Debugf("%#v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	flog.Info("Connection succeeded") | ||||
| 	b.Log.Info("Connection succeeded") | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @@ -60,13 +56,22 @@ func (b *Bsshchat) Send(msg config.Message) (string, error) { | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	b.Log.Debugf("=> Receiving %#v", msg) | ||||
| 	if msg.Extra != nil { | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			b.w.Write([]byte(rmsg.Username + rmsg.Text + "\r\n")) | ||||
| 		} | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			for _, f := range msg.Extra["file"] { | ||||
| 				fi := f.(config.FileInfo) | ||||
| 				if fi.Comment != "" { | ||||
| 					msg.Text += fi.Comment + ": " | ||||
| 				} | ||||
| 				if fi.URL != "" { | ||||
| 					msg.Text = fi.URL | ||||
| 					if fi.Comment != "" { | ||||
| 						msg.Text = fi.Comment + ": " + fi.URL | ||||
| 					} | ||||
| 				} | ||||
| 				b.w.Write([]byte(msg.Username + msg.Text)) | ||||
| 			} | ||||
| @@ -86,10 +91,10 @@ func (b *Bsshchat) sshchatKeepAlive() chan bool { | ||||
| 		for { | ||||
| 			select { | ||||
| 			case <-ticker.C: | ||||
| 				flog.Debugf("PING") | ||||
| 				b.Log.Debugf("PING") | ||||
| 				err := b.xc.PingC2S("", "") | ||||
| 				if err != nil { | ||||
| 					flog.Debugf("PING failed %#v", err) | ||||
| 					b.Log.Debugf("PING failed %#v", err) | ||||
| 				} | ||||
| 			case <-done: | ||||
| 				return | ||||
| @@ -116,6 +121,10 @@ func (b *Bsshchat) handleSshChat() error { | ||||
| 	wait := true | ||||
| 	for { | ||||
| 		if b.r.Scan() { | ||||
| 			// ignore messages from ourselves | ||||
| 			if !strings.Contains(b.r.Text(), "\033[K") { | ||||
| 				continue | ||||
| 			} | ||||
| 			res := strings.Split(stripPrompt(b.r.Text()), ":") | ||||
| 			if res[0] == "-> Set theme" { | ||||
| 				wait = false | ||||
| @@ -123,7 +132,7 @@ func (b *Bsshchat) handleSshChat() error { | ||||
| 				continue | ||||
| 			} | ||||
| 			if !wait { | ||||
| 				flog.Debugf("message %#v", res) | ||||
| 				b.Log.Debugf("<= Message %#v", res) | ||||
| 				rmsg := config.Message{Username: res[0], Text: strings.Join(res[1:], ":"), Channel: "sshchat", Account: b.Account, UserID: "nick"} | ||||
| 				b.Remote <- rmsg | ||||
| 			} | ||||
|   | ||||
| @@ -2,11 +2,13 @@ package bsteam | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	"github.com/Philipp15b/go-steam" | ||||
| 	"github.com/Philipp15b/go-steam/protocol/steamlang" | ||||
| 	"github.com/Philipp15b/go-steam/steamid" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	//"io/ioutil" | ||||
| 	"strconv" | ||||
| 	"sync" | ||||
| @@ -18,31 +20,24 @@ type Bsteam struct { | ||||
| 	connected chan struct{} | ||||
| 	userMap   map[steamid.SteamId]string | ||||
| 	sync.RWMutex | ||||
| 	*config.BridgeConfig | ||||
| 	*bridge.Config | ||||
| } | ||||
|  | ||||
| var flog *log.Entry | ||||
| var protocol = "steam" | ||||
|  | ||||
| func init() { | ||||
| 	flog = log.WithFields(log.Fields{"module": protocol}) | ||||
| } | ||||
|  | ||||
| func New(cfg *config.BridgeConfig) *Bsteam { | ||||
| 	b := &Bsteam{BridgeConfig: cfg} | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	b := &Bsteam{Config: cfg} | ||||
| 	b.userMap = make(map[steamid.SteamId]string) | ||||
| 	b.connected = make(chan struct{}) | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| func (b *Bsteam) Connect() error { | ||||
| 	flog.Info("Connecting") | ||||
| 	b.Log.Info("Connecting") | ||||
| 	b.c = steam.NewClient() | ||||
| 	go b.handleEvents() | ||||
| 	go b.c.Connect() | ||||
| 	select { | ||||
| 	case <-b.connected: | ||||
| 		flog.Info("Connection succeeded") | ||||
| 		b.Log.Info("Connection succeeded") | ||||
| 	case <-time.After(time.Second * 30): | ||||
| 		return fmt.Errorf("connection timed out") | ||||
| 	} | ||||
| @@ -73,6 +68,30 @@ func (b *Bsteam) Send(msg config.Message) (string, error) { | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	// Handle files | ||||
| 	if msg.Extra != nil { | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			b.c.Social.SendMessage(id, steamlang.EChatEntryType_ChatMsg, rmsg.Username+rmsg.Text) | ||||
| 		} | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			for _, f := range msg.Extra["file"] { | ||||
| 				fi := f.(config.FileInfo) | ||||
| 				if fi.Comment != "" { | ||||
| 					msg.Text += fi.Comment + ": " | ||||
| 				} | ||||
| 				if fi.URL != "" { | ||||
| 					msg.Text = fi.URL | ||||
| 					if fi.Comment != "" { | ||||
| 						msg.Text = fi.Comment + ": " + fi.URL | ||||
| 					} | ||||
| 				} | ||||
| 				b.c.Social.SendMessage(id, steamlang.EChatEntryType_ChatMsg, msg.Username+msg.Text) | ||||
| 			} | ||||
| 			return "", nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	b.c.Social.SendMessage(id, steamlang.EChatEntryType_ChatMsg, msg.Username+msg.Text) | ||||
| 	return "", nil | ||||
| } | ||||
| @@ -88,18 +107,18 @@ func (b *Bsteam) getNick(id steamid.SteamId) string { | ||||
|  | ||||
| func (b *Bsteam) handleEvents() { | ||||
| 	myLoginInfo := new(steam.LogOnDetails) | ||||
| 	myLoginInfo.Username = b.Config.Login | ||||
| 	myLoginInfo.Password = b.Config.Password | ||||
| 	myLoginInfo.AuthCode = b.Config.AuthCode | ||||
| 	myLoginInfo.Username = b.GetString("Login") | ||||
| 	myLoginInfo.Password = b.GetString("Password") | ||||
| 	myLoginInfo.AuthCode = b.GetString("AuthCode") | ||||
| 	// Attempt to read existing auth hash to avoid steam guard. | ||||
| 	// Maybe works | ||||
| 	//myLoginInfo.SentryFileHash, _ = ioutil.ReadFile("sentry") | ||||
| 	for event := range b.c.Events() { | ||||
| 		//flog.Info(event) | ||||
| 		//b.Log.Info(event) | ||||
| 		switch e := event.(type) { | ||||
| 		case *steam.ChatMsgEvent: | ||||
| 			flog.Debugf("Receiving ChatMsgEvent: %#v", e) | ||||
| 			flog.Debugf("Sending message from %s on %s to gateway", b.getNick(e.ChatterId), b.Account) | ||||
| 			b.Log.Debugf("Receiving ChatMsgEvent: %#v", e) | ||||
| 			b.Log.Debugf("<= Sending message from %s on %s to gateway", b.getNick(e.ChatterId), b.Account) | ||||
| 			var channel int64 | ||||
| 			if e.ChatRoomId == 0 { | ||||
| 				channel = int64(e.ChatterId) | ||||
| @@ -110,7 +129,7 @@ func (b *Bsteam) handleEvents() { | ||||
| 			msg := config.Message{Username: b.getNick(e.ChatterId), Text: e.Message, Channel: strconv.FormatInt(channel, 10), Account: b.Account, UserID: strconv.FormatInt(int64(e.ChatterId), 10)} | ||||
| 			b.Remote <- msg | ||||
| 		case *steam.PersonaStateEvent: | ||||
| 			flog.Debugf("PersonaStateEvent: %#v\n", e) | ||||
| 			b.Log.Debugf("PersonaStateEvent: %#v\n", e) | ||||
| 			b.Lock() | ||||
| 			b.userMap[e.FriendId] = e.Name | ||||
| 			b.Unlock() | ||||
| @@ -118,47 +137,47 @@ func (b *Bsteam) handleEvents() { | ||||
| 			b.c.Auth.LogOn(myLoginInfo) | ||||
| 		case *steam.MachineAuthUpdateEvent: | ||||
| 			/* | ||||
| 				flog.Info("authupdate", e) | ||||
| 				flog.Info("hash", e.Hash) | ||||
| 				b.Log.Info("authupdate", e) | ||||
| 				b.Log.Info("hash", e.Hash) | ||||
| 				ioutil.WriteFile("sentry", e.Hash, 0666) | ||||
| 			*/ | ||||
| 		case *steam.LogOnFailedEvent: | ||||
| 			flog.Info("Logon failed", e) | ||||
| 			b.Log.Info("Logon failed", e) | ||||
| 			switch e.Result { | ||||
| 			case steamlang.EResult_AccountLogonDeniedNeedTwoFactorCode: | ||||
| 				{ | ||||
| 					flog.Info("Steam guard isn't letting me in! Enter 2FA code:") | ||||
| 					b.Log.Info("Steam guard isn't letting me in! Enter 2FA code:") | ||||
| 					var code string | ||||
| 					fmt.Scanf("%s", &code) | ||||
| 					myLoginInfo.TwoFactorCode = code | ||||
| 				} | ||||
| 			case steamlang.EResult_AccountLogonDenied: | ||||
| 				{ | ||||
| 					flog.Info("Steam guard isn't letting me in! Enter auth code:") | ||||
| 					b.Log.Info("Steam guard isn't letting me in! Enter auth code:") | ||||
| 					var code string | ||||
| 					fmt.Scanf("%s", &code) | ||||
| 					myLoginInfo.AuthCode = code | ||||
| 				} | ||||
| 			default: | ||||
| 				log.Errorf("LogOnFailedEvent: %#v ", e.Result) | ||||
| 				b.Log.Errorf("LogOnFailedEvent: %#v ", e.Result) | ||||
| 				// TODO: Handle EResult_InvalidLoginAuthCode | ||||
| 				return | ||||
| 			} | ||||
| 		case *steam.LoggedOnEvent: | ||||
| 			flog.Debugf("LoggedOnEvent: %#v", e) | ||||
| 			b.Log.Debugf("LoggedOnEvent: %#v", e) | ||||
| 			b.connected <- struct{}{} | ||||
| 			flog.Debugf("setting online") | ||||
| 			b.Log.Debugf("setting online") | ||||
| 			b.c.Social.SetPersonaState(steamlang.EPersonaState_Online) | ||||
| 		case *steam.DisconnectedEvent: | ||||
| 			flog.Info("Disconnected") | ||||
| 			flog.Info("Attempting to reconnect...") | ||||
| 			b.Log.Info("Disconnected") | ||||
| 			b.Log.Info("Attempting to reconnect...") | ||||
| 			b.c.Connect() | ||||
| 		case steam.FatalErrorEvent: | ||||
| 			flog.Error(e) | ||||
| 			b.Log.Error(e) | ||||
| 		case error: | ||||
| 			flog.Error(e) | ||||
| 			b.Log.Error(e) | ||||
| 		default: | ||||
| 			flog.Debugf("unknown event %#v", e) | ||||
| 			b.Log.Debugf("unknown event %#v", e) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -2,15 +2,16 @@ package btelegram | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"github.com/russross/blackfriday" | ||||
| 	"html" | ||||
|  | ||||
| 	"github.com/russross/blackfriday" | ||||
| ) | ||||
|  | ||||
| type customHtml struct { | ||||
| type customHTML struct { | ||||
| 	blackfriday.Renderer | ||||
| } | ||||
|  | ||||
| func (options *customHtml) Paragraph(out *bytes.Buffer, text func() bool) { | ||||
| func (options *customHTML) Paragraph(out *bytes.Buffer, text func() bool) { | ||||
| 	marker := out.Len() | ||||
|  | ||||
| 	if !text() { | ||||
| @@ -20,32 +21,32 @@ func (options *customHtml) Paragraph(out *bytes.Buffer, text func() bool) { | ||||
| 	out.WriteString("\n") | ||||
| } | ||||
|  | ||||
| func (options *customHtml) BlockCode(out *bytes.Buffer, text []byte, lang string) { | ||||
| func (options *customHTML) BlockCode(out *bytes.Buffer, text []byte, lang string) { | ||||
| 	out.WriteString("<pre>") | ||||
|  | ||||
| 	out.WriteString(html.EscapeString(string(text))) | ||||
| 	out.WriteString("</pre>\n") | ||||
| } | ||||
|  | ||||
| func (options *customHtml) Header(out *bytes.Buffer, text func() bool, level int, id string) { | ||||
| func (options *customHTML) Header(out *bytes.Buffer, text func() bool, level int, id string) { | ||||
| 	options.Paragraph(out, text) | ||||
| } | ||||
|  | ||||
| func (options *customHtml) HRule(out *bytes.Buffer) { | ||||
| func (options *customHTML) HRule(out *bytes.Buffer) { | ||||
| 	out.WriteByte('\n') | ||||
| } | ||||
|  | ||||
| func (options *customHtml) BlockQuote(out *bytes.Buffer, text []byte) { | ||||
| func (options *customHTML) BlockQuote(out *bytes.Buffer, text []byte) { | ||||
| 	out.WriteString("> ") | ||||
| 	out.Write(text) | ||||
| 	out.WriteByte('\n') | ||||
| } | ||||
|  | ||||
| func (options *customHtml) List(out *bytes.Buffer, text func() bool, flags int) { | ||||
| func (options *customHTML) List(out *bytes.Buffer, text func() bool, flags int) { | ||||
| 	options.Paragraph(out, text) | ||||
| } | ||||
|  | ||||
| func (options *customHtml) ListItem(out *bytes.Buffer, text []byte, flags int) { | ||||
| func (options *customHTML) ListItem(out *bytes.Buffer, text []byte, flags int) { | ||||
| 	out.WriteString("- ") | ||||
| 	out.Write(text) | ||||
| 	out.WriteByte('\n') | ||||
| @@ -53,7 +54,7 @@ func (options *customHtml) ListItem(out *bytes.Buffer, text []byte, flags int) { | ||||
|  | ||||
| func makeHTML(input string) string { | ||||
| 	return string(blackfriday.Markdown([]byte(input), | ||||
| 		&customHtml{blackfriday.HtmlRenderer(blackfriday.HTML_USE_XHTML|blackfriday.HTML_SKIP_IMAGES, "", "")}, | ||||
| 		&customHTML{blackfriday.HtmlRenderer(blackfriday.HTML_USE_XHTML|blackfriday.HTML_SKIP_IMAGES, "", "")}, | ||||
| 		blackfriday.EXTENSION_NO_INTRA_EMPHASIS| | ||||
| 			blackfriday.EXTENSION_FENCED_CODE| | ||||
| 			blackfriday.EXTENSION_AUTOLINK| | ||||
|   | ||||
| @@ -1,55 +1,49 @@ | ||||
| package btelegram | ||||
|  | ||||
| import ( | ||||
| 	"html" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	"github.com/go-telegram-bot-api/telegram-bot-api" | ||||
| ) | ||||
|  | ||||
| type Btelegram struct { | ||||
| 	c *tgbotapi.BotAPI | ||||
| 	*config.BridgeConfig | ||||
| 	*bridge.Config | ||||
| 	avatarMap map[string]string // keep cache of userid and avatar sha | ||||
| } | ||||
|  | ||||
| var flog *log.Entry | ||||
| var protocol = "telegram" | ||||
|  | ||||
| func init() { | ||||
| 	flog = log.WithFields(log.Fields{"module": protocol}) | ||||
| } | ||||
|  | ||||
| func New(cfg *config.BridgeConfig) *Btelegram { | ||||
| 	return &Btelegram{BridgeConfig: cfg} | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	return &Btelegram{Config: cfg, avatarMap: make(map[string]string)} | ||||
| } | ||||
|  | ||||
| func (b *Btelegram) Connect() error { | ||||
| 	var err error | ||||
| 	flog.Info("Connecting") | ||||
| 	b.c, err = tgbotapi.NewBotAPI(b.Config.Token) | ||||
| 	b.Log.Info("Connecting") | ||||
| 	b.c, err = tgbotapi.NewBotAPI(b.GetString("Token")) | ||||
| 	if err != nil { | ||||
| 		flog.Debugf("%#v", err) | ||||
| 		b.Log.Debugf("%#v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	u := tgbotapi.NewUpdate(0) | ||||
| 	u.Timeout = 60 | ||||
| 	updates, err := b.c.GetUpdatesChan(u) | ||||
| 	if err != nil { | ||||
| 		flog.Debugf("%#v", err) | ||||
| 		b.Log.Debugf("%#v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	flog.Info("Connection succeeded") | ||||
| 	b.Log.Info("Connection succeeded") | ||||
| 	go b.handleRecv(updates) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Btelegram) Disconnect() error { | ||||
| 	return nil | ||||
|  | ||||
| } | ||||
|  | ||||
| func (b *Btelegram) JoinChannel(channel config.ChannelInfo) error { | ||||
| @@ -57,16 +51,24 @@ func (b *Btelegram) JoinChannel(channel config.ChannelInfo) error { | ||||
| } | ||||
|  | ||||
| func (b *Btelegram) Send(msg config.Message) (string, error) { | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	b.Log.Debugf("=> Receiving %#v", msg) | ||||
|  | ||||
| 	// get the chatid | ||||
| 	chatid, err := strconv.ParseInt(msg.Channel, 10, 64) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	if b.Config.MessageFormat == "HTML" { | ||||
| 	// map the file SHA to our user (caches the avatar) | ||||
| 	if msg.Event == config.EVENT_AVATAR_DOWNLOAD { | ||||
| 		return b.cacheAvatar(&msg) | ||||
| 	} | ||||
|  | ||||
| 	if b.GetString("MessageFormat") == "HTML" { | ||||
| 		msg.Text = makeHTML(msg.Text) | ||||
| 	} | ||||
|  | ||||
| 	// Delete message | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		if msg.ID == "" { | ||||
| 			return "", nil | ||||
| @@ -79,14 +81,38 @@ func (b *Btelegram) Send(msg config.Message) (string, error) { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	// Upload a file if it exists | ||||
| 	if msg.Extra != nil { | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			b.sendMessage(chatid, rmsg.Username, rmsg.Text) | ||||
| 		} | ||||
| 		// check if we have files to upload (from slack, telegram or mattermost) | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			b.handleUploadFile(&msg, chatid) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// edit the message if we have a msg ID | ||||
| 	if msg.ID != "" { | ||||
| 		msgid, err := strconv.Atoi(msg.ID) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		if strings.ToLower(b.GetString("MessageFormat")) == "htmlnick" { | ||||
| 			b.Log.Debug("Using mode HTML - nick only") | ||||
| 			msg.Text = html.EscapeString(msg.Text) | ||||
| 		} | ||||
| 		m := tgbotapi.NewEditMessageText(chatid, msgid, msg.Username+msg.Text) | ||||
| 		if b.Config.MessageFormat == "HTML" { | ||||
| 		if b.GetString("MessageFormat") == "HTML" { | ||||
| 			b.Log.Debug("Using mode HTML") | ||||
| 			m.ParseMode = tgbotapi.ModeHTML | ||||
| 		} | ||||
| 		if b.GetString("MessageFormat") == "Markdown" { | ||||
| 			b.Log.Debug("Using mode markdown") | ||||
| 			m.ParseMode = tgbotapi.ModeMarkdown | ||||
| 		} | ||||
| 		if strings.ToLower(b.GetString("MessageFormat")) == "htmlnick" { | ||||
| 			b.Log.Debug("Using mode HTML - nick only") | ||||
| 			m.ParseMode = tgbotapi.ModeHTML | ||||
| 		} | ||||
| 		_, err = b.c.Send(m) | ||||
| @@ -96,98 +122,84 @@ func (b *Btelegram) Send(msg config.Message) (string, error) { | ||||
| 		return "", nil | ||||
| 	} | ||||
|  | ||||
| 	if msg.Extra != nil { | ||||
| 		// check if we have files to upload (from slack, telegram or mattermost) | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			var c tgbotapi.Chattable | ||||
| 			for _, f := range msg.Extra["file"] { | ||||
| 				fi := f.(config.FileInfo) | ||||
| 				file := tgbotapi.FileBytes{fi.Name, *fi.Data} | ||||
| 				re := regexp.MustCompile(".(jpg|png)$") | ||||
| 				if re.MatchString(fi.Name) { | ||||
| 					c = tgbotapi.NewPhotoUpload(chatid, file) | ||||
| 				} else { | ||||
| 					c = tgbotapi.NewDocumentUpload(chatid, file) | ||||
| 				} | ||||
| 				_, err := b.c.Send(c) | ||||
| 				if err != nil { | ||||
| 					log.Errorf("file upload failed: %#v", err) | ||||
| 				} | ||||
| 				if fi.Comment != "" { | ||||
| 					b.sendMessage(chatid, msg.Username+fi.Comment) | ||||
| 				} | ||||
| 			} | ||||
| 			return "", nil | ||||
| 		} | ||||
| 	} | ||||
| 	return b.sendMessage(chatid, msg.Username+msg.Text) | ||||
| 	// Post normal message | ||||
| 	return b.sendMessage(chatid, msg.Username, msg.Text) | ||||
| } | ||||
|  | ||||
| func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { | ||||
| 	for update := range updates { | ||||
| 		flog.Debugf("Receiving from telegram: %#v", update.Message) | ||||
| 		var message *tgbotapi.Message | ||||
| 		username := "" | ||||
| 		channel := "" | ||||
| 		text := "" | ||||
| 		b.Log.Debugf("== Receiving event: %#v", update.Message) | ||||
|  | ||||
| 		fmsg := config.Message{Extra: make(map[string][]interface{})} | ||||
| 		if update.Message == nil && update.ChannelPost == nil && update.EditedMessage == nil && update.EditedChannelPost == nil { | ||||
| 			b.Log.Error("Getting nil messages, this shouldn't happen.") | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		var message *tgbotapi.Message | ||||
|  | ||||
| 		rmsg := config.Message{Account: b.Account, Extra: make(map[string][]interface{})} | ||||
|  | ||||
| 		// handle channels | ||||
| 		if update.ChannelPost != nil { | ||||
| 			message = update.ChannelPost | ||||
| 			rmsg.Text = message.Text | ||||
| 		} | ||||
| 		if update.EditedChannelPost != nil && !b.Config.EditDisable { | ||||
|  | ||||
| 		// edited channel message | ||||
| 		if update.EditedChannelPost != nil && !b.GetBool("EditDisable") { | ||||
| 			message = update.EditedChannelPost | ||||
| 			message.Text = message.Text + b.Config.EditSuffix | ||||
| 			rmsg.Text = rmsg.Text + message.Text + b.GetString("EditSuffix") | ||||
| 		} | ||||
|  | ||||
| 		// handle groups | ||||
| 		if update.Message != nil { | ||||
| 			message = update.Message | ||||
| 			rmsg.Text = message.Text | ||||
| 		} | ||||
| 		if update.EditedMessage != nil && !b.Config.EditDisable { | ||||
|  | ||||
| 		// edited group message | ||||
| 		if update.EditedMessage != nil && !b.GetBool("EditDisable") { | ||||
| 			message = update.EditedMessage | ||||
| 			message.Text = message.Text + b.Config.EditSuffix | ||||
| 			rmsg.Text = rmsg.Text + message.Text + b.GetString("EditSuffix") | ||||
| 		} | ||||
|  | ||||
| 		// set the ID's from the channel or group message | ||||
| 		rmsg.ID = strconv.Itoa(message.MessageID) | ||||
| 		rmsg.Channel = strconv.FormatInt(message.Chat.ID, 10) | ||||
|  | ||||
| 		// handle username | ||||
| 		if message.From != nil { | ||||
| 			if b.Config.UseFirstName { | ||||
| 				username = message.From.FirstName | ||||
| 			rmsg.UserID = strconv.Itoa(message.From.ID) | ||||
| 			if b.GetBool("UseFirstName") { | ||||
| 				rmsg.Username = message.From.FirstName | ||||
| 			} | ||||
| 			if username == "" { | ||||
| 				username = message.From.UserName | ||||
| 				if username == "" { | ||||
| 					username = message.From.FirstName | ||||
| 			if rmsg.Username == "" { | ||||
| 				rmsg.Username = message.From.UserName | ||||
| 				if rmsg.Username == "" { | ||||
| 					rmsg.Username = message.From.FirstName | ||||
| 				} | ||||
| 			} | ||||
| 			text = message.Text | ||||
| 			channel = strconv.FormatInt(message.Chat.ID, 10) | ||||
| 			// only download avatars if we have a place to upload them (configured mediaserver) | ||||
| 			if b.General.MediaServerUpload != "" { | ||||
| 				b.handleDownloadAvatar(message.From.ID, rmsg.Channel) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if username == "" { | ||||
| 			username = "unknown" | ||||
| 		} | ||||
| 		if message.Sticker != nil { | ||||
| 			b.handleDownload(message.Sticker, &fmsg) | ||||
| 		} | ||||
| 		if message.Video != nil { | ||||
| 			b.handleDownload(message.Video, &fmsg) | ||||
| 		} | ||||
| 		if message.Photo != nil { | ||||
| 			b.handleDownload(message.Photo, &fmsg) | ||||
| 		} | ||||
| 		if message.Document != nil { | ||||
| 			b.handleDownload(message.Document, &fmsg) | ||||
| 		} | ||||
| 		if message.Voice != nil { | ||||
| 			b.handleDownload(message.Voice, &fmsg) | ||||
| 		} | ||||
| 		if message.Audio != nil { | ||||
| 			b.handleDownload(message.Audio, &fmsg) | ||||
| 		// if we really didn't find a username, set it to unknown | ||||
| 		if rmsg.Username == "" { | ||||
| 			rmsg.Username = "unknown" | ||||
| 		} | ||||
|  | ||||
| 		// handle any downloads | ||||
| 		err := b.handleDownload(message, &rmsg) | ||||
| 		if err != nil { | ||||
| 			b.Log.Errorf("download failed: %s", err) | ||||
| 		} | ||||
|  | ||||
| 		// handle forwarded messages | ||||
| 		if message.ForwardFrom != nil { | ||||
| 			usernameForward := "" | ||||
| 			if b.Config.UseFirstName { | ||||
| 			if b.GetBool("UseFirstName") { | ||||
| 				usernameForward = message.ForwardFrom.FirstName | ||||
| 			} | ||||
| 			if usernameForward == "" { | ||||
| @@ -199,14 +211,14 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { | ||||
| 			if usernameForward == "" { | ||||
| 				usernameForward = "unknown" | ||||
| 			} | ||||
| 			text = "Forwarded from " + usernameForward + ": " + text | ||||
| 			rmsg.Text = "Forwarded from " + usernameForward + ": " + rmsg.Text | ||||
| 		} | ||||
|  | ||||
| 		// quote the previous message | ||||
| 		if message.ReplyToMessage != nil { | ||||
| 			usernameReply := "" | ||||
| 			if message.ReplyToMessage.From != nil { | ||||
| 				if b.Config.UseFirstName { | ||||
| 				if b.GetBool("UseFirstName") { | ||||
| 					usernameReply = message.ReplyToMessage.From.FirstName | ||||
| 				} | ||||
| 				if usernameReply == "" { | ||||
| @@ -219,14 +231,21 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { | ||||
| 			if usernameReply == "" { | ||||
| 				usernameReply = "unknown" | ||||
| 			} | ||||
| 			text = text + " (re @" + usernameReply + ":" + message.ReplyToMessage.Text + ")" | ||||
| 			if !b.GetBool("QuoteDisable") { | ||||
| 				rmsg.Text = b.handleQuote(rmsg.Text, usernameReply, message.ReplyToMessage.Text) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if text != "" || len(fmsg.Extra) > 0 { | ||||
| 			flog.Debugf("Sending message from %s on %s to gateway", username, b.Account) | ||||
| 			msg := config.Message{Username: username, Text: text, Channel: channel, Account: b.Account, UserID: strconv.Itoa(message.From.ID), ID: strconv.Itoa(message.MessageID), Extra: fmsg.Extra} | ||||
| 			flog.Debugf("Message is %#v", msg) | ||||
| 			b.Remote <- msg | ||||
| 		if rmsg.Text != "" || len(rmsg.Extra) > 0 { | ||||
| 			rmsg.Text = helper.RemoveEmptyNewLines(rmsg.Text) | ||||
| 			// channels don't have (always?) user information. see #410 | ||||
| 			if message.From != nil { | ||||
| 				rmsg.Avatar = helper.GetAvatar(b.avatarMap, strconv.Itoa(message.From.ID), b.General) | ||||
| 			} | ||||
|  | ||||
| 			b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account) | ||||
| 			b.Log.Debugf("<= Message is %#v", rmsg) | ||||
| 			b.Remote <- rmsg | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -239,31 +258,46 @@ func (b *Btelegram) getFileDirectURL(id string) string { | ||||
| 	return res | ||||
| } | ||||
|  | ||||
| func (b *Btelegram) handleDownload(file interface{}, msg *config.Message) { | ||||
| 	size := 0 | ||||
| 	url := "" | ||||
| 	name := "" | ||||
| 	text := "" | ||||
| 	fileid := "" | ||||
| 	switch v := file.(type) { | ||||
| 	case *tgbotapi.Audio: | ||||
| 		size = v.FileSize | ||||
| 		url = b.getFileDirectURL(v.FileID) | ||||
| 		urlPart := strings.Split(url, "/") | ||||
| 		name = urlPart[len(urlPart)-1] | ||||
| 		text = " " + url | ||||
| 		fileid = v.FileID | ||||
| 	case *tgbotapi.Voice: | ||||
| 		size = v.FileSize | ||||
| 		url = b.getFileDirectURL(v.FileID) | ||||
| 		urlPart := strings.Split(url, "/") | ||||
| 		name = urlPart[len(urlPart)-1] | ||||
| 		text = " " + url | ||||
| 		if !strings.HasSuffix(name, ".ogg") { | ||||
| 			name = name + ".ogg" | ||||
| // handleDownloadAvatar downloads the avatar of userid from channel | ||||
| // sends a EVENT_AVATAR_DOWNLOAD message to the gateway if successful. | ||||
| // logs an error message if it fails | ||||
| func (b *Btelegram) handleDownloadAvatar(userid int, channel string) { | ||||
| 	rmsg := config.Message{Username: "system", Text: "avatar", Channel: channel, Account: b.Account, UserID: strconv.Itoa(userid), Event: config.EVENT_AVATAR_DOWNLOAD, Extra: make(map[string][]interface{})} | ||||
| 	if _, ok := b.avatarMap[strconv.Itoa(userid)]; !ok { | ||||
| 		photos, err := b.c.GetUserProfilePhotos(tgbotapi.UserProfilePhotosConfig{UserID: userid, Limit: 1}) | ||||
| 		if err != nil { | ||||
| 			b.Log.Errorf("Userprofile download failed for %#v %s", userid, err) | ||||
| 		} | ||||
| 		fileid = v.FileID | ||||
| 	case *tgbotapi.Sticker: | ||||
|  | ||||
| 		if len(photos.Photos) > 0 { | ||||
| 			photo := photos.Photos[0][0] | ||||
| 			url := b.getFileDirectURL(photo.FileID) | ||||
| 			name := strconv.Itoa(userid) + ".png" | ||||
| 			b.Log.Debugf("trying to download %#v fileid %#v with size %#v", name, photo.FileID, photo.FileSize) | ||||
|  | ||||
| 			err := helper.HandleDownloadSize(b.Log, &rmsg, name, int64(photo.FileSize), b.General) | ||||
| 			if err != nil { | ||||
| 				b.Log.Error(err) | ||||
| 				return | ||||
| 			} | ||||
| 			data, err := helper.DownloadFile(url) | ||||
| 			if err != nil { | ||||
| 				b.Log.Errorf("download %s failed %#v", url, err) | ||||
| 				return | ||||
| 			} | ||||
| 			helper.HandleDownloadData(b.Log, &rmsg, name, rmsg.Text, "", data, b.General) | ||||
| 			b.Remote <- rmsg | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // handleDownloadFile handles file download | ||||
| func (b *Btelegram) handleDownload(message *tgbotapi.Message, rmsg *config.Message) error { | ||||
| 	size := 0 | ||||
| 	var url, name, text string | ||||
|  | ||||
| 	if message.Sticker != nil { | ||||
| 		v := message.Sticker | ||||
| 		size = v.FileSize | ||||
| 		url = b.getFileDirectURL(v.FileID) | ||||
| 		urlPart := strings.Split(url, "/") | ||||
| @@ -272,49 +306,109 @@ func (b *Btelegram) handleDownload(file interface{}, msg *config.Message) { | ||||
| 			name = name + ".webp" | ||||
| 		} | ||||
| 		text = " " + url | ||||
| 		fileid = v.FileID | ||||
| 	case *tgbotapi.Video: | ||||
| 	} | ||||
| 	if message.Video != nil { | ||||
| 		v := message.Video | ||||
| 		size = v.FileSize | ||||
| 		url = b.getFileDirectURL(v.FileID) | ||||
| 		urlPart := strings.Split(url, "/") | ||||
| 		name = urlPart[len(urlPart)-1] | ||||
| 		text = " " + url | ||||
| 		fileid = v.FileID | ||||
| 	case *[]tgbotapi.PhotoSize: | ||||
| 		photos := *v | ||||
| 	} | ||||
| 	if message.Photo != nil { | ||||
| 		photos := *message.Photo | ||||
| 		size = photos[len(photos)-1].FileSize | ||||
| 		url = b.getFileDirectURL(photos[len(photos)-1].FileID) | ||||
| 		urlPart := strings.Split(url, "/") | ||||
| 		name = urlPart[len(urlPart)-1] | ||||
| 		text = " " + url | ||||
| 	case *tgbotapi.Document: | ||||
| 	} | ||||
| 	if message.Document != nil { | ||||
| 		v := message.Document | ||||
| 		size = v.FileSize | ||||
| 		url = b.getFileDirectURL(v.FileID) | ||||
| 		name = v.FileName | ||||
| 		text = " " + v.FileName + " : " + url | ||||
| 		fileid = v.FileID | ||||
| 	} | ||||
| 	if b.Config.UseInsecureURL { | ||||
| 		msg.Text = text | ||||
| 		return | ||||
| 	} | ||||
| 	// if we have a file attached, download it (in memory) and put a pointer to it in msg.Extra | ||||
| 	// limit to 1MB for now | ||||
| 	flog.Debugf("trying to download %#v fileid %#v with size %#v", name, fileid, size) | ||||
| 	if size <= b.General.MediaDownloadSize { | ||||
| 		data, err := helper.DownloadFile(url) | ||||
| 		if err != nil { | ||||
| 			flog.Errorf("download %s failed %#v", url, err) | ||||
| 		} else { | ||||
| 			flog.Debugf("download OK %#v %#v %#v", name, len(*data), len(url)) | ||||
| 			msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{Name: name, Data: data}) | ||||
| 	if message.Voice != nil { | ||||
| 		v := message.Voice | ||||
| 		size = v.FileSize | ||||
| 		url = b.getFileDirectURL(v.FileID) | ||||
| 		urlPart := strings.Split(url, "/") | ||||
| 		name = urlPart[len(urlPart)-1] | ||||
| 		text = " " + url | ||||
| 		if !strings.HasSuffix(name, ".ogg") { | ||||
| 			name = name + ".ogg" | ||||
| 		} | ||||
| 	} | ||||
| 	if message.Audio != nil { | ||||
| 		v := message.Audio | ||||
| 		size = v.FileSize | ||||
| 		url = b.getFileDirectURL(v.FileID) | ||||
| 		urlPart := strings.Split(url, "/") | ||||
| 		name = urlPart[len(urlPart)-1] | ||||
| 		text = " " + url | ||||
| 	} | ||||
| 	// if name is empty we didn't match a thing to download | ||||
| 	if name == "" { | ||||
| 		return nil | ||||
| 	} | ||||
| 	// use the URL instead of native upload | ||||
| 	if b.GetBool("UseInsecureURL") { | ||||
| 		b.Log.Debugf("Setting message text to :%s", text) | ||||
| 		rmsg.Text = rmsg.Text + text | ||||
| 		return nil | ||||
| 	} | ||||
| 	// if we have a file attached, download it (in memory) and put a pointer to it in msg.Extra | ||||
| 	err := helper.HandleDownloadSize(b.Log, rmsg, name, int64(size), b.General) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	data, err := helper.DownloadFile(url) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	helper.HandleDownloadData(b.Log, rmsg, name, message.Caption, "", data, b.General) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Btelegram) sendMessage(chatid int64, text string) (string, error) { | ||||
| 	m := tgbotapi.NewMessage(chatid, text) | ||||
| 	if b.Config.MessageFormat == "HTML" { | ||||
| // handleUploadFile handles native upload of files | ||||
| func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64) (string, error) { | ||||
| 	var c tgbotapi.Chattable | ||||
| 	for _, f := range msg.Extra["file"] { | ||||
| 		fi := f.(config.FileInfo) | ||||
| 		file := tgbotapi.FileBytes{fi.Name, *fi.Data} | ||||
| 		re := regexp.MustCompile(".(jpg|png)$") | ||||
| 		if re.MatchString(fi.Name) { | ||||
| 			c = tgbotapi.NewPhotoUpload(chatid, file) | ||||
| 		} else { | ||||
| 			c = tgbotapi.NewDocumentUpload(chatid, file) | ||||
| 		} | ||||
| 		_, err := b.c.Send(c) | ||||
| 		if err != nil { | ||||
| 			b.Log.Errorf("file upload failed: %#v", err) | ||||
| 		} | ||||
| 		if fi.Comment != "" { | ||||
| 			b.sendMessage(chatid, msg.Username, fi.Comment) | ||||
| 		} | ||||
| 	} | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| func (b *Btelegram) sendMessage(chatid int64, username, text string) (string, error) { | ||||
| 	m := tgbotapi.NewMessage(chatid, "") | ||||
| 	m.Text = username + text | ||||
| 	if b.GetString("MessageFormat") == "HTML" { | ||||
| 		b.Log.Debug("Using mode HTML") | ||||
| 		m.ParseMode = tgbotapi.ModeHTML | ||||
| 	} | ||||
| 	if b.GetString("MessageFormat") == "Markdown" { | ||||
| 		b.Log.Debug("Using mode markdown") | ||||
| 		m.ParseMode = tgbotapi.ModeMarkdown | ||||
| 	} | ||||
| 	if strings.ToLower(b.GetString("MessageFormat")) == "htmlnick" { | ||||
| 		b.Log.Debug("Using mode HTML - nick only") | ||||
| 		m.Text = username + html.EscapeString(text) | ||||
| 		m.ParseMode = tgbotapi.ModeHTML | ||||
| 	} | ||||
| 	res, err := b.c.Send(m) | ||||
| @@ -323,3 +417,25 @@ func (b *Btelegram) sendMessage(chatid int64, text string) (string, error) { | ||||
| 	} | ||||
| 	return strconv.Itoa(res.MessageID), nil | ||||
| } | ||||
|  | ||||
| func (b *Btelegram) cacheAvatar(msg *config.Message) (string, error) { | ||||
| 	fi := msg.Extra["file"][0].(config.FileInfo) | ||||
| 	/* if we have a sha we have successfully uploaded the file to the media server, | ||||
| 	so we can now cache the sha */ | ||||
| 	if fi.SHA != "" { | ||||
| 		b.Log.Debugf("Added %s to %s in avatarMap", fi.SHA, msg.UserID) | ||||
| 		b.avatarMap[msg.UserID] = fi.SHA | ||||
| 	} | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| func (b *Btelegram) handleQuote(message, quoteNick, quoteMessage string) string { | ||||
| 	format := b.GetString("quoteformat") | ||||
| 	if format == "" { | ||||
| 		format = "{MESSAGE} (re @{QUOTENICK}: {QUOTEMESSAGE})" | ||||
| 	} | ||||
| 	format = strings.Replace(format, "{MESSAGE}", message, -1) | ||||
| 	format = strings.Replace(format, "{QUOTENICK}", quoteNick, -1) | ||||
| 	format = strings.Replace(format, "{QUOTEMESSAGE}", quoteMessage, -1) | ||||
| 	return format | ||||
| } | ||||
|   | ||||
| @@ -2,43 +2,38 @@ package bxmpp | ||||
|  | ||||
| import ( | ||||
| 	"crypto/tls" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	"github.com/jpillora/backoff" | ||||
| 	"github.com/mattn/go-xmpp" | ||||
|  | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	"github.com/jpillora/backoff" | ||||
| 	"github.com/matterbridge/go-xmpp" | ||||
| 	"github.com/rs/xid" | ||||
| ) | ||||
|  | ||||
| type Bxmpp struct { | ||||
| 	xc      *xmpp.Client | ||||
| 	xmppMap map[string]string | ||||
| 	*config.BridgeConfig | ||||
| 	*bridge.Config | ||||
| } | ||||
|  | ||||
| var flog *log.Entry | ||||
| var protocol = "xmpp" | ||||
|  | ||||
| func init() { | ||||
| 	flog = log.WithFields(log.Fields{"module": protocol}) | ||||
| } | ||||
|  | ||||
| func New(cfg *config.BridgeConfig) *Bxmpp { | ||||
| 	b := &Bxmpp{BridgeConfig: cfg} | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	b := &Bxmpp{Config: cfg} | ||||
| 	b.xmppMap = make(map[string]string) | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| func (b *Bxmpp) Connect() error { | ||||
| 	var err error | ||||
| 	flog.Infof("Connecting %s", b.Config.Server) | ||||
| 	b.Log.Infof("Connecting %s", b.GetString("Server")) | ||||
| 	b.xc, err = b.createXMPP() | ||||
| 	if err != nil { | ||||
| 		flog.Debugf("%#v", err) | ||||
| 		b.Log.Debugf("%#v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	flog.Info("Connection succeeded") | ||||
| 	b.Log.Info("Connection succeeded") | ||||
| 	go func() { | ||||
| 		initial := true | ||||
| 		bf := &backoff.Backoff{ | ||||
| @@ -48,16 +43,16 @@ func (b *Bxmpp) Connect() error { | ||||
| 		} | ||||
| 		for { | ||||
| 			if initial { | ||||
| 				b.handleXmpp() | ||||
| 				b.handleXMPP() | ||||
| 				initial = false | ||||
| 			} | ||||
| 			d := bf.Duration() | ||||
| 			flog.Infof("Disconnected. Reconnecting in %s", d) | ||||
| 			b.Log.Infof("Disconnected. Reconnecting in %s", d) | ||||
| 			time.Sleep(d) | ||||
| 			b.xc, err = b.createXMPP() | ||||
| 			if err == nil { | ||||
| 				b.Remote <- config.Message{Username: "system", Text: "rejoin", Channel: "", Account: b.Account, Event: config.EVENT_REJOIN_CHANNELS} | ||||
| 				b.handleXmpp() | ||||
| 				b.handleXMPP() | ||||
| 				bf.Reset() | ||||
| 			} | ||||
| 		} | ||||
| @@ -70,53 +65,65 @@ func (b *Bxmpp) Disconnect() error { | ||||
| } | ||||
|  | ||||
| func (b *Bxmpp) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	b.xc.JoinMUCNoHistory(channel.Name+"@"+b.Config.Muc, b.Config.Nick) | ||||
| 	if channel.Options.Key != "" { | ||||
| 		b.Log.Debugf("using key %s for channel %s", channel.Options.Key, channel.Name) | ||||
| 		b.xc.JoinProtectedMUC(channel.Name+"@"+b.GetString("Muc"), b.GetString("Nick"), channel.Options.Key, xmpp.NoHistory, 0, nil) | ||||
| 	} else { | ||||
| 		b.xc.JoinMUCNoHistory(channel.Name+"@"+b.GetString("Muc"), b.GetString("Nick")) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Bxmpp) Send(msg config.Message) (string, error) { | ||||
| 	var msgid = "" | ||||
| 	var msgreplaceid = "" | ||||
| 	// ignore delete messages | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	b.Log.Debugf("=> Receiving %#v", msg) | ||||
|  | ||||
| 	// Upload a file (in xmpp case send the upload URL because xmpp has no native upload support) | ||||
| 	if msg.Extra != nil { | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			b.xc.Send(xmpp.Chat{Type: "groupchat", Remote: rmsg.Channel + "@" + b.GetString("Muc"), Text: rmsg.Username + rmsg.Text}) | ||||
| 		} | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			for _, f := range msg.Extra["file"] { | ||||
| 				fi := f.(config.FileInfo) | ||||
| 				if fi.URL != "" { | ||||
| 					msg.Text = fi.URL | ||||
| 				} | ||||
| 				b.xc.Send(xmpp.Chat{Type: "groupchat", Remote: msg.Channel + "@" + b.Config.Muc, Text: msg.Username + msg.Text}) | ||||
| 			} | ||||
| 			return "", nil | ||||
| 			return b.handleUploadFile(&msg) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	b.xc.Send(xmpp.Chat{Type: "groupchat", Remote: msg.Channel + "@" + b.Config.Muc, Text: msg.Username + msg.Text}) | ||||
| 	return "", nil | ||||
| 	msgid = xid.New().String() | ||||
| 	if msg.ID != "" { | ||||
| 		msgid = msg.ID | ||||
| 		msgreplaceid = msg.ID | ||||
| 	} | ||||
| 	// Post normal message | ||||
| 	_, err := b.xc.Send(xmpp.Chat{Type: "groupchat", Remote: msg.Channel + "@" + b.GetString("Muc"), Text: msg.Username + msg.Text, ID: msgid, ReplaceID: msgreplaceid}) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return msgid, nil | ||||
| } | ||||
|  | ||||
| func (b *Bxmpp) createXMPP() (*xmpp.Client, error) { | ||||
| 	tc := new(tls.Config) | ||||
| 	tc.InsecureSkipVerify = b.Config.SkipTLSVerify | ||||
| 	tc.ServerName = strings.Split(b.Config.Server, ":")[0] | ||||
| 	tc.InsecureSkipVerify = b.GetBool("SkipTLSVerify") | ||||
| 	tc.ServerName = strings.Split(b.GetString("Server"), ":")[0] | ||||
| 	options := xmpp.Options{ | ||||
| 		Host:      b.Config.Server, | ||||
| 		User:      b.Config.Jid, | ||||
| 		Password:  b.Config.Password, | ||||
| 		NoTLS:     true, | ||||
| 		StartTLS:  true, | ||||
| 		TLSConfig: tc, | ||||
|  | ||||
| 		//StartTLS:      false, | ||||
| 		Debug:                        b.General.Debug, | ||||
| 		Host:                         b.GetString("Server"), | ||||
| 		User:                         b.GetString("Jid"), | ||||
| 		Password:                     b.GetString("Password"), | ||||
| 		NoTLS:                        true, | ||||
| 		StartTLS:                     true, | ||||
| 		TLSConfig:                    tc, | ||||
| 		Debug:                        b.GetBool("debug"), | ||||
| 		Logger:                       b.Log.Writer(), | ||||
| 		Session:                      true, | ||||
| 		Status:                       "", | ||||
| 		StatusMessage:                "", | ||||
| 		Resource:                     "", | ||||
| 		InsecureAllowUnencryptedAuth: false, | ||||
| 		//InsecureAllowUnencryptedAuth: true, | ||||
| 	} | ||||
| 	var err error | ||||
| 	b.xc, err = options.NewClient() | ||||
| @@ -131,10 +138,10 @@ func (b *Bxmpp) xmppKeepAlive() chan bool { | ||||
| 		for { | ||||
| 			select { | ||||
| 			case <-ticker.C: | ||||
| 				flog.Debugf("PING") | ||||
| 				b.Log.Debugf("PING") | ||||
| 				err := b.xc.PingC2S("", "") | ||||
| 				if err != nil { | ||||
| 					flog.Debugf("PING failed %#v", err) | ||||
| 					b.Log.Debugf("PING failed %#v", err) | ||||
| 				} | ||||
| 			case <-done: | ||||
| 				return | ||||
| @@ -144,11 +151,11 @@ func (b *Bxmpp) xmppKeepAlive() chan bool { | ||||
| 	return done | ||||
| } | ||||
|  | ||||
| func (b *Bxmpp) handleXmpp() error { | ||||
| func (b *Bxmpp) handleXMPP() error { | ||||
| 	var ok bool | ||||
| 	var msgid string | ||||
| 	done := b.xmppKeepAlive() | ||||
| 	defer close(done) | ||||
| 	nodelay := time.Time{} | ||||
| 	for { | ||||
| 		m, err := b.xc.Recv() | ||||
| 		if err != nil { | ||||
| @@ -156,25 +163,26 @@ func (b *Bxmpp) handleXmpp() error { | ||||
| 		} | ||||
| 		switch v := m.(type) { | ||||
| 		case xmpp.Chat: | ||||
| 			var channel, nick string | ||||
| 			if v.Type == "groupchat" { | ||||
| 				s := strings.Split(v.Remote, "@") | ||||
| 				if len(s) >= 2 { | ||||
| 					channel = s[0] | ||||
| 				b.Log.Debugf("== Receiving %#v", v) | ||||
| 				// skip invalid messages | ||||
| 				if b.skipMessage(v) { | ||||
| 					continue | ||||
| 				} | ||||
| 				s = strings.Split(s[1], "/") | ||||
| 				if len(s) == 2 { | ||||
| 					nick = s[1] | ||||
| 				msgid = v.ID | ||||
| 				if v.ReplaceID != "" { | ||||
| 					msgid = v.ReplaceID | ||||
| 				} | ||||
| 				if nick != b.Config.Nick && v.Stamp == nodelay && v.Text != "" && !strings.Contains(v.Text, "</subject>") { | ||||
| 					rmsg := config.Message{Username: nick, Text: v.Text, Channel: channel, Account: b.Account, UserID: v.Remote} | ||||
| 					rmsg.Text, ok = b.replaceAction(rmsg.Text) | ||||
| 					if ok { | ||||
| 						rmsg.Event = config.EVENT_USER_ACTION | ||||
| 					} | ||||
| 					flog.Debugf("Sending message from %s on %s to gateway", nick, b.Account) | ||||
| 					b.Remote <- rmsg | ||||
| 				rmsg := config.Message{Username: b.parseNick(v.Remote), Text: v.Text, Channel: b.parseChannel(v.Remote), Account: b.Account, UserID: v.Remote, ID: msgid} | ||||
|  | ||||
| 				// check if we have an action event | ||||
| 				rmsg.Text, ok = b.replaceAction(rmsg.Text) | ||||
| 				if ok { | ||||
| 					rmsg.Event = config.EVENT_USER_ACTION | ||||
| 				} | ||||
| 				b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account) | ||||
| 				b.Log.Debugf("<= Message is %#v", rmsg) | ||||
| 				b.Remote <- rmsg | ||||
| 			} | ||||
| 		case xmpp.Presence: | ||||
| 			// do nothing | ||||
| @@ -188,3 +196,71 @@ func (b *Bxmpp) replaceAction(text string) (string, bool) { | ||||
| 	} | ||||
| 	return text, false | ||||
| } | ||||
|  | ||||
| // handleUploadFile handles native upload of files | ||||
| func (b *Bxmpp) handleUploadFile(msg *config.Message) (string, error) { | ||||
| 	var urldesc = "" | ||||
|  | ||||
| 	for _, f := range msg.Extra["file"] { | ||||
| 		fi := f.(config.FileInfo) | ||||
| 		if fi.Comment != "" { | ||||
| 			msg.Text += fi.Comment + ": " | ||||
| 		} | ||||
| 		if fi.URL != "" { | ||||
| 			msg.Text = fi.URL | ||||
| 			if fi.Comment != "" { | ||||
| 				msg.Text = fi.Comment + ": " + fi.URL | ||||
| 				urldesc = fi.Comment | ||||
| 			} | ||||
| 		} | ||||
| 		_, err := b.xc.Send(xmpp.Chat{Type: "groupchat", Remote: msg.Channel + "@" + b.GetString("Muc"), Text: msg.Username + msg.Text}) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		if fi.URL != "" { | ||||
| 			b.xc.SendOOB(xmpp.Chat{Type: "groupchat", Remote: msg.Channel + "@" + b.GetString("Muc"), Ooburl: fi.URL, Oobdesc: urldesc}) | ||||
| 		} | ||||
| 	} | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| func (b *Bxmpp) parseNick(remote string) string { | ||||
| 	s := strings.Split(remote, "@") | ||||
| 	if len(s) > 0 { | ||||
| 		s = strings.Split(s[1], "/") | ||||
| 		if len(s) == 2 { | ||||
| 			return s[1] // nick | ||||
| 		} | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (b *Bxmpp) parseChannel(remote string) string { | ||||
| 	s := strings.Split(remote, "@") | ||||
| 	if len(s) >= 2 { | ||||
| 		return s[0] // channel | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| // skipMessage skips messages that need to be skipped | ||||
| func (b *Bxmpp) skipMessage(message xmpp.Chat) bool { | ||||
| 	// skip messages from ourselves | ||||
| 	if b.parseNick(message.Remote) == b.GetString("Nick") { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	// skip empty messages | ||||
| 	if message.Text == "" { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	// skip subject messages | ||||
| 	if strings.Contains(message.Text, "</subject>") { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	// skip delayed messages | ||||
| 	t := time.Time{} | ||||
| 	return message.Stamp != t | ||||
| } | ||||
|   | ||||
							
								
								
									
										170
									
								
								bridge/zulip/zulip.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								bridge/zulip/zulip.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,170 @@ | ||||
| package bzulip | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"io/ioutil" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	gzb "github.com/matterbridge/gozulipbot" | ||||
| ) | ||||
|  | ||||
| type Bzulip struct { | ||||
| 	q       *gzb.Queue | ||||
| 	bot     *gzb.Bot | ||||
| 	streams map[int]string | ||||
| 	*bridge.Config | ||||
| } | ||||
|  | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	return &Bzulip{Config: cfg, streams: make(map[int]string)} | ||||
| } | ||||
|  | ||||
| func (b *Bzulip) Connect() error { | ||||
| 	bot := gzb.Bot{APIKey: b.GetString("token"), APIURL: b.GetString("server") + "/api/v1/", Email: b.GetString("login")} | ||||
| 	bot.Init() | ||||
| 	q, err := bot.RegisterAll() | ||||
| 	b.q = q | ||||
| 	b.bot = &bot | ||||
| 	if err != nil { | ||||
| 		b.Log.Errorf("Connect() %#v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	// init stream | ||||
| 	b.getChannel(0) | ||||
| 	b.Log.Info("Connection succeeded") | ||||
| 	go b.handleQueue() | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Bzulip) Disconnect() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Bzulip) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Bzulip) Send(msg config.Message) (string, error) { | ||||
| 	b.Log.Debugf("=> Receiving %#v", msg) | ||||
|  | ||||
| 	// Delete message | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		if msg.ID == "" { | ||||
| 			return "", nil | ||||
| 		} | ||||
| 		_, err := b.bot.UpdateMessage(msg.ID, "") | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	// Upload a file if it exists | ||||
| 	if msg.Extra != nil { | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			b.sendMessage(rmsg) | ||||
| 		} | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			return b.handleUploadFile(&msg) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// edit the message if we have a msg ID | ||||
| 	if msg.ID != "" { | ||||
| 		_, err := b.bot.UpdateMessage(msg.ID, msg.Username+msg.Text) | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	// Post normal message | ||||
| 	return b.sendMessage(msg) | ||||
| } | ||||
|  | ||||
| func (b *Bzulip) getChannel(id int) string { | ||||
| 	if name, ok := b.streams[id]; ok { | ||||
| 		return name | ||||
| 	} | ||||
| 	streams, err := b.bot.GetRawStreams() | ||||
| 	if err != nil { | ||||
| 		b.Log.Errorf("getChannel: %#v", err) | ||||
| 		return "" | ||||
| 	} | ||||
| 	for _, stream := range streams.Streams { | ||||
| 		b.streams[stream.StreamID] = stream.Name | ||||
| 	} | ||||
| 	if name, ok := b.streams[id]; ok { | ||||
| 		return name | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (b *Bzulip) handleQueue() error { | ||||
| 	for { | ||||
| 		messages, _ := b.q.GetEvents() | ||||
| 		for _, m := range messages { | ||||
| 			b.Log.Debugf("== Receiving %#v", m) | ||||
| 			// ignore our own messages | ||||
| 			if m.SenderEmail == b.GetString("login") { | ||||
| 				continue | ||||
| 			} | ||||
| 			rmsg := config.Message{Username: m.SenderFullName, Text: m.Content, Channel: b.getChannel(m.StreamID), Account: b.Account, UserID: strconv.Itoa(m.SenderID), Avatar: m.AvatarURL} | ||||
| 			b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account) | ||||
| 			b.Log.Debugf("<= Message is %#v", rmsg) | ||||
| 			b.Remote <- rmsg | ||||
| 			b.q.LastEventID = m.ID | ||||
| 		} | ||||
| 		time.Sleep(time.Second * 3) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Bzulip) sendMessage(msg config.Message) (string, error) { | ||||
| 	topic := "matterbridge" | ||||
| 	if b.GetString("topic") != "" { | ||||
| 		topic = b.GetString("topic") | ||||
| 	} | ||||
| 	m := gzb.Message{ | ||||
| 		Stream:  msg.Channel, | ||||
| 		Topic:   topic, | ||||
| 		Content: msg.Username + msg.Text, | ||||
| 	} | ||||
| 	resp, err := b.bot.Message(m) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	if resp != nil { | ||||
| 		defer resp.Body.Close() | ||||
| 		res, err := ioutil.ReadAll(resp.Body) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		var jr struct { | ||||
| 			ID int `json:"id"` | ||||
| 		} | ||||
| 		err = json.Unmarshal(res, &jr) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		return strconv.Itoa(jr.ID), nil | ||||
| 	} | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| func (b *Bzulip) handleUploadFile(msg *config.Message) (string, error) { | ||||
| 	for _, f := range msg.Extra["file"] { | ||||
| 		fi := f.(config.FileInfo) | ||||
| 		if fi.Comment != "" { | ||||
| 			msg.Text += fi.Comment + ": " | ||||
| 		} | ||||
| 		if fi.URL != "" { | ||||
| 			msg.Text = fi.URL | ||||
| 			if fi.Comment != "" { | ||||
| 				msg.Text = fi.Comment + ": " + fi.URL | ||||
| 			} | ||||
| 		} | ||||
| 		_, err := b.sendMessage(*msg) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 	} | ||||
| 	return "", nil | ||||
| } | ||||
							
								
								
									
										121
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										121
									
								
								changelog.md
									
									
									
									
									
								
							| @@ -1,3 +1,124 @@ | ||||
| # v1.11.2 | ||||
|  | ||||
| ## Bugfix | ||||
| * slack: fix slack API changes regarding to files/images | ||||
|  | ||||
| # v1.11.1 | ||||
|  | ||||
| ## New features | ||||
| * slack: Add support for slack channels by ID. Closes #436 | ||||
| * discord: Clip too long messages sent to discord (discord). Closes #440 | ||||
|  | ||||
| ## Bugfix | ||||
| * general: fix possible panic on downloads that are too big #448 | ||||
| * general: Fix avatar uploads to work with MediaDownloadPath. Closes #454 | ||||
| * discord: allow receiving of topic changes/channel leave/joins from other bridges through the webhook | ||||
| * discord: Add a space before url in file uploads (discord). Closes #461 | ||||
| * discord:  Skip empty messages being sent with the webhook (discord). #469 | ||||
| * mattermost: Use nickname instead of username if defined (mattermost). Closes #452 | ||||
| * irc: Stop numbers being stripped after non-color control codes (irc) (#465) | ||||
| * slack: Use UserID to look for avatar instead of username (slack). Closes #472 | ||||
|  | ||||
| # v1.11.0 | ||||
|  | ||||
| ## New features | ||||
| * general: Add config option MediaDownloadPath (#443). See `MediaDownloadPath` in matterbridge.toml.sample | ||||
| * general: Add MediaDownloadBlacklist option. Closes #442. See `MediaDownloadBlacklist` in matterbridge.toml.sample | ||||
| * xmpp: Add channel password support for XMPP (#451) | ||||
| * xmpp: Add message correction support for XMPP (#437) | ||||
| * telegram: Add support for MessageFormat=htmlnick (telegram). #444 | ||||
| * mattermost: Add support for mattermost 5.x | ||||
|  | ||||
| ## Enhancements | ||||
| * slack: Add Title from attachment slack message (#446) | ||||
| * irc: Prevent white or black color codes (irc) (#434) | ||||
|  | ||||
| ## Bugfix | ||||
| * slack: Fix regexp in replaceMention (slack). (#435) | ||||
| * irc: Reconnect on quit. (irc) See #431 (#445) | ||||
| * sshchat: Ignore messages from ourself. (sshchat) Closes #439 | ||||
|  | ||||
| # v1.10.1 | ||||
| ## New features | ||||
| * irc: Colorize username sent to IRC using its crc32 IEEE checksum (#423). See `ColorNicks` in matterbridge.toml.sample | ||||
| * irc: Add support for CJK to/from utf-8 (irc). #400 | ||||
| * telegram: Add QuoteFormat option (telegram). Closes #413. See `QuoteFormat` in matterbridge.toml.sample | ||||
| * xmpp: Send attached files to XMPP in different message with OOB data and without body (#421) | ||||
|  | ||||
| ## Bugfix | ||||
| * general: updated irc/xmpp/telegram libraries | ||||
| * mattermost/slack/rocketchat: Fix iconurl regression. Closes #430 | ||||
| * mattermost/slack: Use uuid instead of userid. Fixes #429 | ||||
| * slack: Avatar spoofing from Slack to Discord with uppercase in nick doesn't work (#433) | ||||
| * irc: Fix format string bug (irc) (#428) | ||||
|  | ||||
| # v1.10.0 | ||||
| ## New features | ||||
| * general: Add support for reloading all settings automatically after changing config except connection and gateway configuration. Closes #373 | ||||
| * zulip: New protocol support added (https://zulipchat.com) | ||||
|  | ||||
| ## Enhancements | ||||
| * general: Handle file comment better | ||||
| * steam: Handle file uploads to mediaserver (steam) | ||||
| * slack: Properly set Slack user who initiated slash command (#394) | ||||
|  | ||||
| ## Bugfix | ||||
| * general: Use only alphanumeric for file uploads to mediaserver. Closes #416 | ||||
| * general: Fix crash on invalid filenames | ||||
| * general: Fix regression in ReplaceMessages and ReplaceNicks. Closes #407 | ||||
| * telegram: Fix possible nil when using channels (telegram). #410 | ||||
| * telegram: Fix panic (telegram). Closes #410 | ||||
| * telegram: Handle channel posts correctly | ||||
| * mattermost: Update GetFileLinks to API_V4 | ||||
|  | ||||
| # v1.9.1 | ||||
| ## New features | ||||
| * telegram: Add QuoteDisable option (telegram). Closes #399. See QuoteDisable in matterbridge.toml.sample | ||||
| ## Enhancements | ||||
| * discord: Send mediaserver link to Discord in Webhook mode (discord) (#405) | ||||
| * mattermost: Print list of valid team names when team not found (#390) | ||||
| * slack: Strip markdown URLs with blank text (slack) (#392) | ||||
| ## Bugfix | ||||
| * slack/mattermost: Make our callbackid more unique. Fixes issue with running multiple matterbridge on the same channel (slack,mattermost) | ||||
| * telegram: fix newlines in multiline messages #399 | ||||
| * telegram: Revert #378 | ||||
|  | ||||
| # v1.9.0 (the refactor release) | ||||
| ## New features | ||||
| * general: better debug messages | ||||
| * general: better support for environment variables override | ||||
| * general: Ability to disable sending join/leave messages to other gateways. #382 | ||||
| * slack: Allow Slack @usergroups to be parsed as human-friendly names #379 | ||||
| * slack: Provide better context for shared posts from Slack<=>Slack enhancement #369 | ||||
| * telegram: Convert nicks automatically into HTML when MessageFormat is set to HTML #378 | ||||
| * irc: Add DebugLevel option  | ||||
|  | ||||
| ## Bugfix | ||||
| * slack: Ignore restricted_action on channel join (slack). Closes #387 | ||||
| * slack: Add slack attachment support to matterhook | ||||
| * slack: Update userlist on join (slack). Closes #372 | ||||
|  | ||||
| # v1.8.0 | ||||
| ## New features | ||||
| * general: Send chat notification if media is too big to be re-uploaded to MediaServer. See #359 | ||||
| * general: Download (and upload) avatar images from mattermost and telegram when mediaserver is configured. Closes #362 | ||||
| * general: Add label support in RemoteNickFormat | ||||
| * general: Prettier info/debug log output | ||||
| * mattermost: Download files and reupload to supported bridges (mattermost). Closes #357 | ||||
| * slack: Add ShowTopicChange option. Allow/disable topic change messages (currently only from slack). Closes #353 | ||||
| * slack: Add support for file comments (slack). Closes #346 | ||||
| * telegram: Add comment to file upload from telegram. Show comments on all bridges. Closes #358 | ||||
| * telegram: Add markdown support (telegram). #355 | ||||
| * api: Give api access to whole config.Message (and events). Closes #374 | ||||
|  | ||||
| ## Bugfix | ||||
| * discord: Check for a valid WebhookURL (discord). Closes #367 | ||||
| * discord: Fix role mention replace issues | ||||
| * irc: Truncate messages sent to IRC based on byte count (#368) | ||||
| * mattermost: Add file download urls also to mattermost webhooks #356 | ||||
| * telegram: Fix panic on nil messages (telegram). Closes #366 | ||||
| * telegram: Fix the UseInsecureURL text (telegram). Closes #184 | ||||
|  | ||||
| # v1.7.1 | ||||
| ## Bugfix | ||||
| * telegram: Enable Long Polling for Telegram. Reduces bandwidth consumption. (#350) | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| #!/bin/bash | ||||
| go version |grep go1.9 || exit | ||||
| go version |grep go1.10 || exit | ||||
| VERSION=$(git describe --tags) | ||||
| mkdir ci/binaries | ||||
| GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-windows-amd64.exe | ||||
|   | ||||
| @@ -3,17 +3,35 @@ package gateway | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/api" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	bdiscord "github.com/42wim/matterbridge/bridge/discord" | ||||
| 	bgitter "github.com/42wim/matterbridge/bridge/gitter" | ||||
| 	birc "github.com/42wim/matterbridge/bridge/irc" | ||||
| 	bmatrix "github.com/42wim/matterbridge/bridge/matrix" | ||||
| 	bmattermost "github.com/42wim/matterbridge/bridge/mattermost" | ||||
| 	brocketchat "github.com/42wim/matterbridge/bridge/rocketchat" | ||||
| 	bslack "github.com/42wim/matterbridge/bridge/slack" | ||||
| 	bsshchat "github.com/42wim/matterbridge/bridge/sshchat" | ||||
| 	bsteam "github.com/42wim/matterbridge/bridge/steam" | ||||
| 	btelegram "github.com/42wim/matterbridge/bridge/telegram" | ||||
| 	bxmpp "github.com/42wim/matterbridge/bridge/xmpp" | ||||
| 	bzulip "github.com/42wim/matterbridge/bridge/zulip" | ||||
| 	"github.com/hashicorp/golang-lru" | ||||
| 	log "github.com/sirupsen/logrus" | ||||
| 	//	"github.com/davecgh/go-spew/spew" | ||||
| 	"crypto/sha1" | ||||
| 	"github.com/hashicorp/golang-lru" | ||||
| 	"github.com/peterhellberg/emojilib" | ||||
| 	"net/http" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/peterhellberg/emojilib" | ||||
| ) | ||||
|  | ||||
| type Gateway struct { | ||||
| @@ -34,6 +52,28 @@ type BrMsgID struct { | ||||
| 	ChannelID string | ||||
| } | ||||
|  | ||||
| var flog *log.Entry | ||||
|  | ||||
| var bridgeMap = map[string]bridge.Factory{ | ||||
| 	"api":        api.New, | ||||
| 	"discord":    bdiscord.New, | ||||
| 	"gitter":     bgitter.New, | ||||
| 	"irc":        birc.New, | ||||
| 	"mattermost": bmattermost.New, | ||||
| 	"matrix":     bmatrix.New, | ||||
| 	"rocketchat": brocketchat.New, | ||||
| 	"slack":      bslack.New, | ||||
| 	"sshchat":    bsshchat.New, | ||||
| 	"steam":      bsteam.New, | ||||
| 	"telegram":   btelegram.New, | ||||
| 	"xmpp":       bxmpp.New, | ||||
| 	"zulip":      bzulip.New, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	flog = log.WithFields(log.Fields{"prefix": "gateway"}) | ||||
| } | ||||
|  | ||||
| func New(cfg config.Gateway, r *Router) *Gateway { | ||||
| 	gw := &Gateway{Channels: make(map[string]*config.ChannelInfo), Message: r.Message, | ||||
| 		Router: r, Bridges: make(map[string]*bridge.Bridge), Config: r.Config} | ||||
| @@ -46,7 +86,14 @@ func New(cfg config.Gateway, r *Router) *Gateway { | ||||
| func (gw *Gateway) AddBridge(cfg *config.Bridge) error { | ||||
| 	br := gw.Router.getBridge(cfg.Account) | ||||
| 	if br == nil { | ||||
| 		br = bridge.New(gw.Config, cfg, gw.Message) | ||||
| 		br = bridge.New(cfg) | ||||
| 		br.Config = gw.Router.Config | ||||
| 		br.General = &gw.General | ||||
| 		// set logging | ||||
| 		br.Log = log.WithFields(log.Fields{"prefix": "bridge"}) | ||||
| 		brconfig := &bridge.Config{Remote: gw.Message, Log: log.WithFields(log.Fields{"prefix": br.Protocol}), Bridge: br} | ||||
| 		// add the actual bridger for this protocol to this bridge using the bridgeMap | ||||
| 		br.Bridger = bridgeMap[br.Protocol](brconfig) | ||||
| 	} | ||||
| 	gw.mapChannelsToBridge(br) | ||||
| 	gw.Bridges[cfg.Account] = br | ||||
| @@ -78,10 +125,10 @@ func (gw *Gateway) reconnectBridge(br *bridge.Bridge) { | ||||
| 	br.Disconnect() | ||||
| 	time.Sleep(time.Second * 5) | ||||
| RECONNECT: | ||||
| 	log.Infof("Reconnecting %s", br.Account) | ||||
| 	flog.Infof("Reconnecting %s", br.Account) | ||||
| 	err := br.Connect() | ||||
| 	if err != nil { | ||||
| 		log.Errorf("Reconnection failed: %s. Trying again in 60 seconds", err) | ||||
| 		flog.Errorf("Reconnection failed: %s. Trying again in 60 seconds", err) | ||||
| 		time.Sleep(time.Second * 60) | ||||
| 		goto RECONNECT | ||||
| 	} | ||||
| @@ -145,7 +192,7 @@ func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []con | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// do samechannelgateway logic | ||||
| 		// do samechannelgateway flogic | ||||
| 		if channel.SameChannel[msg.Gateway] { | ||||
| 			if msg.Channel == channel.Name && msg.Account != dest.Account { | ||||
| 				channels = append(channels, *channel) | ||||
| @@ -162,39 +209,55 @@ func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []con | ||||
| func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) []*BrMsgID { | ||||
| 	var brMsgIDs []*BrMsgID | ||||
|  | ||||
| 	// TODO refactor | ||||
| 	// only slack now, check will have to be done in the different bridges. | ||||
| 	// we need to check if we can't use fallback or text in other bridges | ||||
| 	// if we have an attached file, or other info | ||||
| 	if msg.Extra != nil { | ||||
| 		if dest.Protocol != "discord" && | ||||
| 			dest.Protocol != "slack" && | ||||
| 			dest.Protocol != "mattermost" && | ||||
| 			dest.Protocol != "telegram" && | ||||
| 			dest.Protocol != "matrix" && | ||||
| 			dest.Protocol != "xmpp" { | ||||
| 		if len(msg.Extra[config.EVENT_FILE_FAILURE_SIZE]) != 0 { | ||||
| 			if msg.Text == "" { | ||||
| 				return brMsgIDs | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	// only relay join/part when configged | ||||
| 	if msg.Event == config.EVENT_JOIN_LEAVE && !gw.Bridges[dest.Account].Config.ShowJoinPart { | ||||
|  | ||||
| 	// Avatar downloads are only relevant for telegram and mattermost for now | ||||
| 	if msg.Event == config.EVENT_AVATAR_DOWNLOAD { | ||||
| 		if dest.Protocol != "mattermost" && | ||||
| 			dest.Protocol != "telegram" { | ||||
| 			return brMsgIDs | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// only relay join/part when configured | ||||
| 	if msg.Event == config.EVENT_JOIN_LEAVE && !gw.Bridges[dest.Account].GetBool("ShowJoinPart") { | ||||
| 		return brMsgIDs | ||||
| 	} | ||||
|  | ||||
| 	// only relay topic change when configured | ||||
| 	if msg.Event == config.EVENT_TOPIC_CHANGE && !gw.Bridges[dest.Account].GetBool("ShowTopicChange") { | ||||
| 		return brMsgIDs | ||||
| 	} | ||||
|  | ||||
| 	// broadcast to every out channel (irc QUIT) | ||||
| 	if msg.Channel == "" && msg.Event != config.EVENT_JOIN_LEAVE { | ||||
| 		log.Debug("empty channel") | ||||
| 		flog.Debug("empty channel") | ||||
| 		return brMsgIDs | ||||
| 	} | ||||
|  | ||||
| 	originchannel := msg.Channel | ||||
| 	origmsg := msg | ||||
| 	channels := gw.getDestChannel(&msg, *dest) | ||||
| 	for _, channel := range channels { | ||||
| 		// do not send to ourself | ||||
| 		if channel.ID == getChannelID(origmsg) { | ||||
| 			continue | ||||
| 		// Only send the avatar download event to ourselves. | ||||
| 		if msg.Event == config.EVENT_AVATAR_DOWNLOAD { | ||||
| 			if channel.ID != getChannelID(origmsg) { | ||||
| 				continue | ||||
| 			} | ||||
| 		} else { | ||||
| 			// do not send to ourself for any other event | ||||
| 			if channel.ID == getChannelID(origmsg) { | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
| 		log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel.Name) | ||||
| 		flog.Debugf("=> Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel.Name) | ||||
| 		msg.Channel = channel.Name | ||||
| 		msg.Avatar = gw.modifyAvatar(origmsg, dest) | ||||
| 		msg.Username = gw.modifyUsername(origmsg, dest) | ||||
| @@ -215,10 +278,11 @@ func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) []*BrM | ||||
| 		} | ||||
| 		mID, err := dest.Send(msg) | ||||
| 		if err != nil { | ||||
| 			fmt.Println(err) | ||||
| 			flog.Error(err) | ||||
| 		} | ||||
| 		// append the message ID (mID) from this bridge (dest) to our brMsgIDs slice | ||||
| 		if mID != "" { | ||||
| 			flog.Debugf("mID %s: %s", dest.Account, mID) | ||||
| 			brMsgIDs = append(brMsgIDs, &BrMsgID{dest, mID, channel.ID}) | ||||
| 		} | ||||
| 	} | ||||
| @@ -230,30 +294,39 @@ func (gw *Gateway) ignoreMessage(msg *config.Message) bool { | ||||
| 	if _, ok := gw.Bridges[msg.Account]; !ok { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	// check if we need to ignore a empty message | ||||
| 	if msg.Text == "" { | ||||
| 		// we have an attachment or actual bytes | ||||
| 		if msg.Extra != nil && (msg.Extra["attachments"] != nil || len(msg.Extra["file"]) > 0) { | ||||
| 		// we have an attachment or actual bytes, do not ignore | ||||
| 		if msg.Extra != nil && | ||||
| 			(msg.Extra["attachments"] != nil || | ||||
| 				len(msg.Extra["file"]) > 0 || | ||||
| 				len(msg.Extra[config.EVENT_FILE_FAILURE_SIZE]) > 0) { | ||||
| 			return false | ||||
| 		} | ||||
| 		log.Debugf("ignoring empty message %#v from %s", msg, msg.Account) | ||||
| 		flog.Debugf("ignoring empty message %#v from %s", msg, msg.Account) | ||||
| 		return true | ||||
| 	} | ||||
| 	for _, entry := range strings.Fields(gw.Bridges[msg.Account].Config.IgnoreNicks) { | ||||
|  | ||||
| 	// is the username in IgnoreNicks field | ||||
| 	for _, entry := range strings.Fields(gw.Bridges[msg.Account].GetString("IgnoreNicks")) { | ||||
| 		if msg.Username == entry { | ||||
| 			log.Debugf("ignoring %s from %s", msg.Username, msg.Account) | ||||
| 			flog.Debugf("ignoring %s from %s", msg.Username, msg.Account) | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// does the message match regex in IgnoreMessages field | ||||
| 	// TODO do not compile regexps everytime | ||||
| 	for _, entry := range strings.Fields(gw.Bridges[msg.Account].Config.IgnoreMessages) { | ||||
| 	for _, entry := range strings.Fields(gw.Bridges[msg.Account].GetString("IgnoreMessages")) { | ||||
| 		if entry != "" { | ||||
| 			re, err := regexp.Compile(entry) | ||||
| 			if err != nil { | ||||
| 				log.Errorf("incorrect regexp %s for %s", entry, msg.Account) | ||||
| 				flog.Errorf("incorrect regexp %s for %s", entry, msg.Account) | ||||
| 				continue | ||||
| 			} | ||||
| 			if re.MatchString(msg.Text) { | ||||
| 				log.Debugf("matching %s. ignoring %s from %s", entry, msg.Text, msg.Account) | ||||
| 				flog.Debugf("matching %s. ignoring %s from %s", entry, msg.Text, msg.Account) | ||||
| 				return true | ||||
| 			} | ||||
| 		} | ||||
| @@ -264,23 +337,23 @@ func (gw *Gateway) ignoreMessage(msg *config.Message) bool { | ||||
| func (gw *Gateway) modifyUsername(msg config.Message, dest *bridge.Bridge) string { | ||||
| 	br := gw.Bridges[msg.Account] | ||||
| 	msg.Protocol = br.Protocol | ||||
| 	if gw.Config.General.StripNick || dest.Config.StripNick { | ||||
| 	if gw.Config.General.StripNick || dest.GetBool("StripNick") { | ||||
| 		re := regexp.MustCompile("[^a-zA-Z0-9]+") | ||||
| 		msg.Username = re.ReplaceAllString(msg.Username, "") | ||||
| 	} | ||||
| 	nick := dest.Config.RemoteNickFormat | ||||
| 	nick := dest.GetString("RemoteNickFormat") | ||||
| 	if nick == "" { | ||||
| 		nick = gw.Config.General.RemoteNickFormat | ||||
| 	} | ||||
|  | ||||
| 	// loop to replace nicks | ||||
| 	for _, outer := range br.Config.ReplaceNicks { | ||||
| 	for _, outer := range br.GetStringSlice2D("ReplaceNicks") { | ||||
| 		search := outer[0] | ||||
| 		replace := outer[1] | ||||
| 		// TODO move compile to bridge init somewhere | ||||
| 		re, err := regexp.Compile(search) | ||||
| 		if err != nil { | ||||
| 			log.Errorf("regexp in %s failed: %s", msg.Account, err) | ||||
| 			flog.Errorf("regexp in %s failed: %s", msg.Account, err) | ||||
| 			break | ||||
| 		} | ||||
| 		msg.Username = re.ReplaceAllString(msg.Username, replace) | ||||
| @@ -298,8 +371,10 @@ func (gw *Gateway) modifyUsername(msg config.Message, dest *bridge.Bridge) strin | ||||
| 		} | ||||
| 		nick = strings.Replace(nick, "{NOPINGNICK}", msg.Username[:i]+""+msg.Username[i:], -1) | ||||
| 	} | ||||
|  | ||||
| 	nick = strings.Replace(nick, "{BRIDGE}", br.Name, -1) | ||||
| 	nick = strings.Replace(nick, "{PROTOCOL}", br.Protocol, -1) | ||||
| 	nick = strings.Replace(nick, "{LABEL}", br.GetString("Label"), -1) | ||||
| 	nick = strings.Replace(nick, "{NICK}", msg.Username, -1) | ||||
| 	return nick | ||||
| } | ||||
| @@ -307,7 +382,7 @@ func (gw *Gateway) modifyUsername(msg config.Message, dest *bridge.Bridge) strin | ||||
| func (gw *Gateway) modifyAvatar(msg config.Message, dest *bridge.Bridge) string { | ||||
| 	iconurl := gw.Config.General.IconURL | ||||
| 	if iconurl == "" { | ||||
| 		iconurl = dest.Config.IconURL | ||||
| 		iconurl = dest.GetString("IconURL") | ||||
| 	} | ||||
| 	iconurl = strings.Replace(iconurl, "{NICK}", msg.Username, -1) | ||||
| 	if msg.Avatar == "" { | ||||
| @@ -319,15 +394,16 @@ func (gw *Gateway) modifyAvatar(msg config.Message, dest *bridge.Bridge) string | ||||
| func (gw *Gateway) modifyMessage(msg *config.Message) { | ||||
| 	// replace :emoji: to unicode | ||||
| 	msg.Text = emojilib.Replace(msg.Text) | ||||
|  | ||||
| 	br := gw.Bridges[msg.Account] | ||||
| 	// loop to replace messages | ||||
| 	for _, outer := range br.Config.ReplaceMessages { | ||||
| 	for _, outer := range br.GetStringSlice2D("ReplaceMessages") { | ||||
| 		search := outer[0] | ||||
| 		replace := outer[1] | ||||
| 		// TODO move compile to bridge init somewhere | ||||
| 		re, err := regexp.Compile(search) | ||||
| 		if err != nil { | ||||
| 			log.Errorf("regexp in %s failed: %s", msg.Account, err) | ||||
| 			flog.Errorf("regexp in %s failed: %s", msg.Account, err) | ||||
| 			break | ||||
| 		} | ||||
| 		msg.Text = re.ReplaceAllString(msg.Text, replace) | ||||
| @@ -339,42 +415,94 @@ func (gw *Gateway) modifyMessage(msg *config.Message) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // handleFiles uploads or places all files on the given msg to the MediaServer and | ||||
| // adds the new URL of the file on the MediaServer onto the given msg. | ||||
| func (gw *Gateway) handleFiles(msg *config.Message) { | ||||
| 	if msg.Extra == nil || gw.Config.General.MediaServerUpload == "" { | ||||
| 	reg := regexp.MustCompile("[^a-zA-Z0-9]+") | ||||
|  | ||||
| 	// If we don't have a attachfield or we don't have a mediaserver configured return | ||||
| 	if msg.Extra == nil || (gw.Config.General.MediaServerUpload == "" && gw.Config.General.MediaDownloadPath == "") { | ||||
| 		return | ||||
| 	} | ||||
| 	if len(msg.Extra["file"]) > 0 { | ||||
| 		client := &http.Client{ | ||||
| 			Timeout: time.Second * 5, | ||||
| 		} | ||||
| 		for i, f := range msg.Extra["file"] { | ||||
| 			fi := f.(config.FileInfo) | ||||
| 			sha1sum := fmt.Sprintf("%x", sha1.Sum(*fi.Data)) | ||||
| 			reader := bytes.NewReader(*fi.Data) | ||||
| 			url := gw.Config.General.MediaServerUpload + "/" + sha1sum + "/" + fi.Name | ||||
| 			durl := gw.Config.General.MediaServerDownload + "/" + sha1sum + "/" + fi.Name | ||||
| 			extra := msg.Extra["file"][i].(config.FileInfo) | ||||
| 			extra.URL = durl | ||||
| 			msg.Extra["file"][i] = extra | ||||
| 			req, _ := http.NewRequest("PUT", url, reader) | ||||
| 			req.Header.Set("Content-Type", "binary/octet-stream") | ||||
| 			_, err := client.Do(req) | ||||
| 			if err != nil { | ||||
| 				log.Errorf("mediaserver upload failed: %#v", err) | ||||
| 			} | ||||
| 			log.Debugf("mediaserver download URL = %s", durl) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func getChannelID(msg config.Message) string { | ||||
| 	return msg.Channel + msg.Account | ||||
| 	// If we don't have files, nothing to upload. | ||||
| 	if len(msg.Extra["file"]) == 0 { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	client := &http.Client{ | ||||
| 		Timeout: time.Second * 5, | ||||
| 	} | ||||
|  | ||||
| 	for i, f := range msg.Extra["file"] { | ||||
| 		fi := f.(config.FileInfo) | ||||
| 		ext := filepath.Ext(fi.Name) | ||||
| 		fi.Name = fi.Name[0 : len(fi.Name)-len(ext)] | ||||
| 		fi.Name = reg.ReplaceAllString(fi.Name, "_") | ||||
| 		fi.Name = fi.Name + ext | ||||
|  | ||||
| 		sha1sum := fmt.Sprintf("%x", sha1.Sum(*fi.Data))[:8] | ||||
|  | ||||
| 		if gw.Config.General.MediaServerUpload != "" { | ||||
| 			// Use MediaServerUpload. Upload using a PUT HTTP request and basicauth. | ||||
|  | ||||
| 			url := gw.Config.General.MediaServerUpload + "/" + sha1sum + "/" + fi.Name | ||||
|  | ||||
| 			req, err := http.NewRequest("PUT", url, bytes.NewReader(*fi.Data)) | ||||
| 			if err != nil { | ||||
| 				flog.Errorf("mediaserver upload failed, could not create request: %#v", err) | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			flog.Debugf("mediaserver upload url: %s", url) | ||||
|  | ||||
| 			req.Header.Set("Content-Type", "binary/octet-stream") | ||||
| 			_, err = client.Do(req) | ||||
| 			if err != nil { | ||||
| 				flog.Errorf("mediaserver upload failed, could not Do request: %#v", err) | ||||
| 				continue | ||||
| 			} | ||||
| 		} else { | ||||
| 			// Use MediaServerPath. Place the file on the current filesystem. | ||||
|  | ||||
| 			dir := gw.Config.General.MediaDownloadPath + "/" + sha1sum | ||||
| 			err := os.Mkdir(dir, os.ModePerm) | ||||
| 			if err != nil && !os.IsExist(err) { | ||||
| 				flog.Errorf("mediaserver path failed, could not mkdir: %s %#v", err, err) | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			path := dir + "/" + fi.Name | ||||
| 			flog.Debugf("mediaserver path placing file: %s", path) | ||||
|  | ||||
| 			err = ioutil.WriteFile(path, *fi.Data, os.ModePerm) | ||||
| 			if err != nil { | ||||
| 				flog.Errorf("mediaserver path failed, could not writefile: %s %#v", err, err) | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Download URL. | ||||
| 		durl := gw.Config.General.MediaServerDownload + "/" + sha1sum + "/" + fi.Name | ||||
|  | ||||
| 		flog.Debugf("mediaserver download URL = %s", durl) | ||||
|  | ||||
| 		// We uploaded/placed the file successfully. Add the SHA and URL. | ||||
| 		extra := msg.Extra["file"][i].(config.FileInfo) | ||||
| 		extra.URL = durl | ||||
| 		extra.SHA = sha1sum | ||||
| 		msg.Extra["file"][i] = extra | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (gw *Gateway) validGatewayDest(msg *config.Message, channel *config.ChannelInfo) bool { | ||||
| 	return msg.Gateway == gw.Name | ||||
| } | ||||
|  | ||||
| func getChannelID(msg config.Message) string { | ||||
| 	return msg.Channel + msg.Account | ||||
| } | ||||
|  | ||||
| func isApi(account string) bool { | ||||
| 	return strings.HasPrefix(account, "api.") | ||||
| } | ||||
|   | ||||
| @@ -2,15 +2,15 @@ package gateway | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/BurntSushi/toml" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| var testconfig = ` | ||||
| var testconfig = []byte(` | ||||
| [irc.freenode] | ||||
| [mattermost.test] | ||||
| [gitter.42wim] | ||||
| @@ -37,9 +37,9 @@ var testconfig = ` | ||||
|     [[gateway.inout]] | ||||
|     account="slack.test" | ||||
|     channel="testing" | ||||
| 	` | ||||
| 	`) | ||||
|  | ||||
| var testconfig2 = ` | ||||
| var testconfig2 = []byte(` | ||||
| [irc.freenode] | ||||
| [mattermost.test] | ||||
| [gitter.42wim] | ||||
| @@ -80,8 +80,9 @@ var testconfig2 = ` | ||||
|     [[gateway.out]] | ||||
|     account = "discord.test" | ||||
|     channel = "general2" | ||||
| 	` | ||||
| var testconfig3 = ` | ||||
| 	`) | ||||
|  | ||||
| var testconfig3 = []byte(` | ||||
| [irc.zzz] | ||||
| [telegram.zzz] | ||||
| [slack.zzz] | ||||
| @@ -149,13 +150,10 @@ enable=true | ||||
|     [[gateway.inout]] | ||||
|     account="telegram.zzz" | ||||
|     channel="--333333333333" | ||||
| ` | ||||
| `) | ||||
|  | ||||
| func maketestRouter(input string) *Router { | ||||
| 	var cfg *config.Config | ||||
| 	if _, err := toml.Decode(input, &cfg); err != nil { | ||||
| 		fmt.Println(err) | ||||
| 	} | ||||
| func maketestRouter(input []byte) *Router { | ||||
| 	cfg := config.NewConfigFromString(input) | ||||
| 	r, err := NewRouter(cfg) | ||||
| 	if err != nil { | ||||
| 		fmt.Println(err) | ||||
| @@ -163,14 +161,7 @@ func maketestRouter(input string) *Router { | ||||
| 	return r | ||||
| } | ||||
| func TestNewRouter(t *testing.T) { | ||||
| 	var cfg *config.Config | ||||
| 	if _, err := toml.Decode(testconfig, &cfg); err != nil { | ||||
| 		fmt.Println(err) | ||||
| 	} | ||||
| 	r, err := NewRouter(cfg) | ||||
| 	if err != nil { | ||||
| 		fmt.Println(err) | ||||
| 	} | ||||
| 	r := maketestRouter(testconfig) | ||||
| 	assert.Equal(t, 1, len(r.Gateways)) | ||||
| 	assert.Equal(t, 4, len(r.Gateways["bridge1"].Bridges)) | ||||
| 	assert.Equal(t, 4, len(r.Gateways["bridge1"].Channels)) | ||||
|   | ||||
| @@ -2,10 +2,10 @@ package gateway | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/gateway/samechannel" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	samechannelgateway "github.com/42wim/matterbridge/gateway/samechannel" | ||||
| 	//	"github.com/davecgh/go-spew/spew" | ||||
| 	"time" | ||||
| ) | ||||
| @@ -17,10 +17,7 @@ type Router struct { | ||||
| } | ||||
|  | ||||
| func NewRouter(cfg *config.Config) (*Router, error) { | ||||
| 	r := &Router{} | ||||
| 	r.Config = cfg | ||||
| 	r.Message = make(chan config.Message) | ||||
| 	r.Gateways = make(map[string]*Gateway) | ||||
| 	r := &Router{Message: make(chan config.Message), Gateways: make(map[string]*Gateway), Config: cfg} | ||||
| 	sgw := samechannelgateway.New(cfg) | ||||
| 	gwconfigs := sgw.GetConfig() | ||||
|  | ||||
| @@ -42,12 +39,13 @@ func NewRouter(cfg *config.Config) (*Router, error) { | ||||
| func (r *Router) Start() error { | ||||
| 	m := make(map[string]*bridge.Bridge) | ||||
| 	for _, gw := range r.Gateways { | ||||
| 		flog.Infof("Parsing gateway %s", gw.Name) | ||||
| 		for _, br := range gw.Bridges { | ||||
| 			m[br.Account] = br | ||||
| 		} | ||||
| 	} | ||||
| 	for _, br := range m { | ||||
| 		log.Infof("Starting bridge: %s ", br.Account) | ||||
| 		flog.Infof("Starting bridge: %s ", br.Account) | ||||
| 		err := br.Connect() | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("Bridge %s failed to start: %v", br.Account, err) | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package samechannelgateway | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/BurntSushi/toml" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|   | ||||
							
								
								
									
										83
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| module github.com/42wim/matterbridge | ||||
|  | ||||
| require ( | ||||
| 	github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557 | ||||
| 	github.com/BurntSushi/toml v0.0.0-20170318202913-d94612f9fc14 | ||||
| 	github.com/Philipp15b/go-steam v0.0.0-20161020161927-e0f3bb9566e3 | ||||
| 	github.com/Sirupsen/logrus v1.0.6 // indirect | ||||
| 	github.com/alecthomas/log4go v0.0.0-20160307011253-e5dc62318d9b // indirect | ||||
| 	github.com/bwmarrin/discordgo v0.0.0-20180201002541-8d5ab59c63e5 // indirect | ||||
| 	github.com/davecgh/go-spew v1.1.0 // indirect | ||||
| 	github.com/dfordsoft/golib v0.0.0-20180313113957-2ea3495aee1d | ||||
| 	github.com/dgrijalva/jwt-go v0.0.0-20170508165458-6c8dedd55f8a // indirect | ||||
| 	github.com/fsnotify/fsnotify v1.4.7 | ||||
| 	github.com/go-telegram-bot-api/telegram-bot-api v0.0.0-20180428185002-212b1541150c | ||||
| 	github.com/golang/protobuf v0.0.0-20170613224224-e325f446bebc // indirect | ||||
| 	github.com/google/gops v0.0.0-20170319002943-62f833fc9f6c | ||||
| 	github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f // indirect | ||||
| 	github.com/gorilla/schema v0.0.0-20170317173100-f3c80893412c | ||||
| 	github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777 | ||||
| 	github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad | ||||
| 	github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb // indirect | ||||
| 	github.com/hpcloud/tail v1.0.0 // indirect | ||||
| 	github.com/jpillora/backoff v0.0.0-20170222002228-06c7a16c845d | ||||
| 	github.com/jtolds/gls v4.2.1+incompatible // indirect | ||||
| 	github.com/kardianos/osext v0.0.0-20170207191655-9b883c5eb462 // indirect | ||||
| 	github.com/kr/pretty v0.1.0 // indirect | ||||
| 	github.com/labstack/echo v0.0.0-20180219162101-7eec915044a1 | ||||
| 	github.com/labstack/gommon v0.2.1 // indirect | ||||
| 	github.com/lrstanley/girc v0.0.0-20180427160007-102f17f86306 | ||||
| 	github.com/magiconair/properties v0.0.0-20180217134545-2c9e95027885 // indirect | ||||
| 	github.com/matterbridge/discordgo v0.0.0-20180806170629-ef40ff5ba64f | ||||
| 	github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91 | ||||
| 	github.com/matterbridge/gomatrix v0.0.0-20171224233421-78ac6a1a0f5f | ||||
| 	github.com/matterbridge/gozulipbot v0.0.0-20180507190239-b6bb12d33544 | ||||
| 	github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61 | ||||
| 	github.com/mattermost/platform v4.6.2+incompatible | ||||
| 	github.com/mattn/go-colorable v0.0.0-20170210172801-5411d3eea597 // indirect | ||||
| 	github.com/mattn/go-isatty v0.0.0-20170216235908-dda3de49cbfc // indirect | ||||
| 	github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect | ||||
| 	github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238 // indirect | ||||
| 	github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474 // indirect | ||||
| 	github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff // indirect | ||||
| 	github.com/nicksnyder/go-i18n v1.4.0 // indirect | ||||
| 	github.com/nlopes/slack v0.3.1-0.20180805133408-21749ab136a8 | ||||
| 	github.com/onsi/ginkgo v1.6.0 // indirect | ||||
| 	github.com/onsi/gomega v1.4.1 // indirect | ||||
| 	github.com/paulrosania/go-charset v0.0.0-20151028000031-621bb39fcc83 | ||||
| 	github.com/pborman/uuid v0.0.0-20160216163710-c55201b03606 // indirect | ||||
| 	github.com/pelletier/go-toml v0.0.0-20180228233631-05bcc0fb0d3e // indirect | ||||
| 	github.com/peterhellberg/emojilib v0.0.0-20170616163716-41920917e271 | ||||
| 	github.com/pkg/errors v0.8.0 // indirect | ||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||
| 	github.com/rs/xid v0.0.0-20180525034800-088c5cf1423a | ||||
| 	github.com/russross/blackfriday v1.5.1 | ||||
| 	github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca | ||||
| 	github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1 // indirect | ||||
| 	github.com/shazow/ssh-chat v0.0.0-20171012174035-2078e1381991 | ||||
| 	github.com/sirupsen/logrus v0.0.0-20180213143110-8c0189d9f6bb | ||||
| 	github.com/smartystreets/assertions v0.0.0-20180803164922-886ec427f6b9 // indirect | ||||
| 	github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect | ||||
| 	github.com/spf13/afero v0.0.0-20180211162714-bbf41cb36dff // indirect | ||||
| 	github.com/spf13/cast v1.2.0 // indirect | ||||
| 	github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec // indirect | ||||
| 	github.com/spf13/pflag v0.0.0-20180220143236-ee5fd03fd6ac // indirect | ||||
| 	github.com/spf13/viper v0.0.0-20171227194143-aafc9e6bc7b7 | ||||
| 	github.com/stretchr/testify v0.0.0-20170714215325-05e8a0eda380 | ||||
| 	github.com/technoweenie/multipartstreamer v1.0.1 // indirect | ||||
| 	github.com/valyala/bytebufferpool v0.0.0-20160817181652-e746df99fe4a // indirect | ||||
| 	github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 // indirect | ||||
| 	github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect | ||||
| 	github.com/zfjagann/golang-ring v0.0.0-20141111230621-17637388c9f6 | ||||
| 	golang.org/x/crypto v0.0.0-20180228161326-91a49db82a88 // indirect | ||||
| 	golang.org/x/net v0.0.0-20180108090419-434ec0c7fe37 // indirect | ||||
| 	golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect | ||||
| 	golang.org/x/sys v0.0.0-20171130163741-8b4580aae2a0 // indirect | ||||
| 	golang.org/x/text v0.0.0-20180511172408-5c1cf69b5978 // indirect | ||||
| 	gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect | ||||
| 	gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect | ||||
| 	gopkg.in/fsnotify.v1 v1.4.7 // indirect | ||||
| 	gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.1 // indirect | ||||
| 	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect | ||||
| 	gopkg.in/yaml.v2 v2.0.0-20160301204022-a83829b6f129 // indirect | ||||
| ) | ||||
							
								
								
									
										163
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,163 @@ | ||||
| github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557 h1:IZtuWGfzQnKnCSu+vl8WGLhpVQ5Uvy3rlSwqXSg+sQg= | ||||
| github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557/go.mod h1:jL0YSXMs/txjtGJ4PWrmETOk6KUHMDPMshgQZlTeB3Y= | ||||
| github.com/BurntSushi/toml v0.0.0-20170318202913-d94612f9fc14 h1:v/zr4ns/4sSahF9KBm4Uc933bLsEEv7LuT63CJ019yo= | ||||
| github.com/BurntSushi/toml v0.0.0-20170318202913-d94612f9fc14/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | ||||
| github.com/Philipp15b/go-steam v0.0.0-20161020161927-e0f3bb9566e3 h1:V4+1E1SRYUySqwOoI3ZphFADtabbF568zTHa5ix/zU0= | ||||
| github.com/Philipp15b/go-steam v0.0.0-20161020161927-e0f3bb9566e3/go.mod h1:HuVM+sZFzumUdKPWiz+IlCMb4RdsKdT3T+nQBKL+sYg= | ||||
| github.com/Sirupsen/logrus v1.0.6 h1:HCAGQRk48dRVPA5Y+Yh0qdCSTzPOyU1tBJ7Q9YzotII= | ||||
| github.com/Sirupsen/logrus v1.0.6/go.mod h1:rmk17hk6i8ZSAJkSDa7nOxamrG+SP4P0mm+DAvExv4U= | ||||
| github.com/alecthomas/log4go v0.0.0-20160307011253-e5dc62318d9b h1:1OpGXps6UOY5HtQaQcLowsV1qMWCNBzhFvK7q4fgXtc= | ||||
| github.com/alecthomas/log4go v0.0.0-20160307011253-e5dc62318d9b/go.mod h1:iCVmQ9g4TfaRX5m5jq5sXY7RXYWPv9/PynM/GocbG3w= | ||||
| github.com/bwmarrin/discordgo v0.0.0-20180201002541-8d5ab59c63e5 h1:M7u44DKGpA5goDIBf0zRMYhT1Sp2Rd7hiTzXfeuw1UY= | ||||
| github.com/bwmarrin/discordgo v0.0.0-20180201002541-8d5ab59c63e5/go.mod h1:5NIvFv5Z7HddYuXbuQegZ684DleQaCFqChP2iuBivJ8= | ||||
| github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | ||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/dfordsoft/golib v0.0.0-20180313113957-2ea3495aee1d h1:rONNnZDE5CYuaSFQk+gP4GEQTXEUcyQ5p6p/dgxIHas= | ||||
| github.com/dfordsoft/golib v0.0.0-20180313113957-2ea3495aee1d/go.mod h1:UGa5M2Sz/Uh13AMse4+RELKCDw7kqgqlTjeGae+7vUY= | ||||
| github.com/dgrijalva/jwt-go v0.0.0-20170508165458-6c8dedd55f8a h1:MuHMeSsXbNEeUyxjB7T9P8s1+5k8OLTC/M27qsVwixM= | ||||
| github.com/dgrijalva/jwt-go v0.0.0-20170508165458-6c8dedd55f8a/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= | ||||
| github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= | ||||
| github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | ||||
| github.com/go-telegram-bot-api/telegram-bot-api v0.0.0-20180428185002-212b1541150c h1:3gMh737vMGqAkkkSfNbwjO8VRHOSaCjYRG4y9xVMEIQ= | ||||
| github.com/go-telegram-bot-api/telegram-bot-api v0.0.0-20180428185002-212b1541150c/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= | ||||
| github.com/golang/protobuf v0.0.0-20170613224224-e325f446bebc h1:wdhDSKrkYy24mcfzuA3oYm58h0QkyXjwERCkzJDP5kA= | ||||
| github.com/golang/protobuf v0.0.0-20170613224224-e325f446bebc/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||||
| github.com/google/gops v0.0.0-20170319002943-62f833fc9f6c h1:MrMA1vhRTNidtgENqmsmLOIUS6ixMBOU/g10rm7IUe8= | ||||
| github.com/google/gops v0.0.0-20170319002943-62f833fc9f6c/go.mod h1:pMQgrscwEK/aUSW1IFSaBPbJX82FPHWaSoJw1axQfD0= | ||||
| github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f h1:FDM3EtwZLyhW48YRiyqjivNlNZjAObv4xt4NnJaU+NQ= | ||||
| github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | ||||
| github.com/gorilla/schema v0.0.0-20170317173100-f3c80893412c h1:mORYpib1aLu3M2Oi50Z1pNTXuDJEHcoLb6oo6VdOutk= | ||||
| github.com/gorilla/schema v0.0.0-20170317173100-f3c80893412c/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= | ||||
| github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777 h1:JIM+OacoOJRU30xpjMf8sulYqjr0ViA3WDrTX6j/yDI= | ||||
| github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= | ||||
| github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad h1:eMxs9EL0PvIGS9TTtxg4R+JxuPGav82J8rA+GFnY7po= | ||||
| github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= | ||||
| github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb h1:1OvvPvZkn/yCQ3xBcM8y4020wdkMXPHLB4+NfoGWh4U= | ||||
| github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= | ||||
| github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= | ||||
| github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | ||||
| github.com/jpillora/backoff v0.0.0-20170222002228-06c7a16c845d h1:ETeT81zgLgSNc4BWdDO2Fg9ekVItYErbNtE8mKD2pJA= | ||||
| github.com/jpillora/backoff v0.0.0-20170222002228-06c7a16c845d/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= | ||||
| github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= | ||||
| github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | ||||
| github.com/kardianos/osext v0.0.0-20170207191655-9b883c5eb462 h1:oSOOTPHkCzMeu1vJ0nHxg5+XZBdMMjNa+6NPnm8arok= | ||||
| github.com/kardianos/osext v0.0.0-20170207191655-9b883c5eb462/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= | ||||
| github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= | ||||
| github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= | ||||
| github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | ||||
| github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= | ||||
| github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | ||||
| github.com/labstack/echo v0.0.0-20180219162101-7eec915044a1 h1:cOIt0LZKdfeirAfTP4VtIJuWbjVTGtd1suuPXp/J+dE= | ||||
| github.com/labstack/echo v0.0.0-20180219162101-7eec915044a1/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s= | ||||
| github.com/labstack/gommon v0.2.1 h1:C+I4NYknueQncqKYZQ34kHsLZJVeB5KwPUhnO0nmbpU= | ||||
| github.com/labstack/gommon v0.2.1/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4= | ||||
| github.com/lrstanley/girc v0.0.0-20180427160007-102f17f86306 h1:IqN61cmi7LM/IaYaP9a/KXFtHRS2a3+WHu8GhAXJT7c= | ||||
| github.com/lrstanley/girc v0.0.0-20180427160007-102f17f86306/go.mod h1:7cRs1SIBfKQ7e3Tam6GKTILSNHzR862JD0JpINaZoJk= | ||||
| github.com/magiconair/properties v0.0.0-20180217134545-2c9e95027885 h1:HWxJJvF+QceKcql4r9PC93NtMEgEBfBxlQrZPvbcQvs= | ||||
| github.com/magiconair/properties v0.0.0-20180217134545-2c9e95027885/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= | ||||
| github.com/matterbridge/discordgo v0.0.0-20180806170629-ef40ff5ba64f h1:9IIOO9Aznn8zJx3nokZ4U6nfuzWw5xAlygPvuRZMisQ= | ||||
| github.com/matterbridge/discordgo v0.0.0-20180806170629-ef40ff5ba64f/go.mod h1:5QtN542bJn9FunZqYlIbleNtToxfLCVV9pW7m7Q42Fc= | ||||
| github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91 h1:KzDEcy8eDbTx881giW8a6llsAck3e2bJvMyKvh1IK+k= | ||||
| github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91/go.mod h1:ECDRehsR9TYTKCAsRS8/wLeOk6UUqDydw47ln7wG41Q= | ||||
| github.com/matterbridge/gomatrix v0.0.0-20171224233421-78ac6a1a0f5f h1:2eKh6Qi/sJ8bXvYMoyVfQxHgR8UcCDWjOmhV1oCstMU= | ||||
| github.com/matterbridge/gomatrix v0.0.0-20171224233421-78ac6a1a0f5f/go.mod h1:+jWeaaUtXQbBRdKYWfjW6JDDYiI2XXE+3NnTjW5kg8g= | ||||
| github.com/matterbridge/gozulipbot v0.0.0-20180507190239-b6bb12d33544 h1:A8lLG3DAu75B5jITHs9z4JBmU6oCq1WiUNnDAmqKCZc= | ||||
| github.com/matterbridge/gozulipbot v0.0.0-20180507190239-b6bb12d33544/go.mod h1:yAjnZ34DuDyPHMPHHjOsTk/FefW4JJjoMMCGt/8uuQA= | ||||
| github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61 h1:R/MgM/eUyRBQx2FiH6JVmXck8PaAuKfe2M1tWIzW7nE= | ||||
| github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61/go.mod h1:iXGEotOvwI1R1SjLxRc+BF5rUORTMtE0iMZBT2lxqAU= | ||||
| github.com/mattermost/platform v4.6.2+incompatible h1:9WqKNuJFIp6SDYn5wl1RF5urdhEw8d7o5tAOwT1MW0A= | ||||
| github.com/mattermost/platform v4.6.2+incompatible/go.mod h1:HjGKtkQNu3HXTOykPMQckMnH11WHvNvQqDBNnVXVbfM= | ||||
| github.com/mattn/go-colorable v0.0.0-20170210172801-5411d3eea597 h1:hGizH4aMDFFt1iOA4HNKC13lqIBoCyxIjWcAnWIy7aU= | ||||
| github.com/mattn/go-colorable v0.0.0-20170210172801-5411d3eea597/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= | ||||
| github.com/mattn/go-isatty v0.0.0-20170216235908-dda3de49cbfc h1:pK7tzC30erKOTfEDCYGvPZQCkmM9X5iSmmAR5m9x3Yc= | ||||
| github.com/mattn/go-isatty v0.0.0-20170216235908-dda3de49cbfc/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= | ||||
| github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= | ||||
| github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= | ||||
| github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238 h1:+MZW2uvHgN8kYvksEN3f7eFL2wpzk0GxmlFsMybWc7E= | ||||
| github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | ||||
| github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474 h1:oKIteTqeSpenyTrOVj5zkiyCaflLa8B+CD0324otT+o= | ||||
| github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= | ||||
| github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff h1:HLGD5/9UxxfEuO9DtP8gnTmNtMxbPyhYltfxsITel8g= | ||||
| github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff/go.mod h1:B8jLfIIPn2sKyWr0D7cL2v7tnrDD5z291s2Zypdu89E= | ||||
| github.com/nicksnyder/go-i18n v1.4.0 h1:AgLl+Yq7kg5OYlzCgu9cKTZOyI4tD/NgukKqLqC8E+I= | ||||
| github.com/nicksnyder/go-i18n v1.4.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= | ||||
| github.com/nlopes/slack v0.0.0-20180101221843-107290b5bbaf h1:M+xGhDxie/MqC+tzs+3ZHBSY4Wsv+fEkrpIMCKy8PTg= | ||||
| github.com/nlopes/slack v0.0.0-20180101221843-107290b5bbaf/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= | ||||
| github.com/nlopes/slack v0.3.1-0.20180805133408-21749ab136a8 h1:PSy8NkmkyldLmPPnNNw7mwfQFOHDqOI6bINpJ+/KV7Y= | ||||
| github.com/nlopes/slack v0.3.1-0.20180805133408-21749ab136a8/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= | ||||
| github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= | ||||
| github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | ||||
| github.com/onsi/gomega v1.4.1 h1:PZSj/UFNaVp3KxrzHOcS7oyuWA7LoOY/77yCTEFu21U= | ||||
| github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= | ||||
| github.com/paulrosania/go-charset v0.0.0-20151028000031-621bb39fcc83 h1:XQonH5Iv5rbyIkMJOQ4xKmKHQTh8viXtRSmep5Ca5I4= | ||||
| github.com/paulrosania/go-charset v0.0.0-20151028000031-621bb39fcc83/go.mod h1:YnNlZP7l4MhyGQ4CBRwv6ohZTPrUJJZtEv4ZgADkbs4= | ||||
| github.com/pborman/uuid v0.0.0-20160216163710-c55201b03606 h1:/CPgDYrfeK2LMK6xcUhvI17yO9SlpAdDIJGkhDEgO8A= | ||||
| github.com/pborman/uuid v0.0.0-20160216163710-c55201b03606/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= | ||||
| github.com/pelletier/go-toml v0.0.0-20180228233631-05bcc0fb0d3e h1:ZW8599OjioQsmBbkGpyruHUlRVQceYFWnJsGr4NCkiA= | ||||
| github.com/pelletier/go-toml v0.0.0-20180228233631-05bcc0fb0d3e/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= | ||||
| github.com/peterhellberg/emojilib v0.0.0-20170616163716-41920917e271 h1:wQ9lVx75za6AT2kI0S9QID0uWuwTWnvcTfN+uw1F8vg= | ||||
| github.com/peterhellberg/emojilib v0.0.0-20170616163716-41920917e271/go.mod h1:G7LufuPajuIvdt9OitkNt2qh0mmvD4bfRgRM7bhDIOA= | ||||
| github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= | ||||
| github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/rs/xid v0.0.0-20180525034800-088c5cf1423a h1:UWKek6MK3K6/TpbsFcv+8rrO6rSc6KKSp2FbMOHWsq4= | ||||
| github.com/rs/xid v0.0.0-20180525034800-088c5cf1423a/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= | ||||
| github.com/russross/blackfriday v1.5.1 h1:B8ZN6pD4PVofmlDCDUdELeYrbsVIDM/bpjW3v3zgcRc= | ||||
| github.com/russross/blackfriday v1.5.1/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= | ||||
| github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI= | ||||
| github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= | ||||
| github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1 h1:Lx3BlDGFElJt4u/zKc9A3BuGYbQAGlEFyPuUA3jeMD0= | ||||
| github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1/go.mod h1:vt2jWY/3Qw1bIzle5thrJWucsLuuX9iUNnp20CqCciI= | ||||
| github.com/shazow/ssh-chat v0.0.0-20171012174035-2078e1381991 h1:PQiUTDzUC5EUh0vNurK7KQS22zlKqLLOFn+K9nJXDQQ= | ||||
| github.com/shazow/ssh-chat v0.0.0-20171012174035-2078e1381991/go.mod h1:KwtnpMClmrXsHCKTbRui5xBUNt17n1GGrGhdiw2KcoY= | ||||
| github.com/sirupsen/logrus v0.0.0-20180213143110-8c0189d9f6bb h1:eKjx20EiekBRT2tjZ0XEdKpftfPJQwiavtFshwTyqf0= | ||||
| github.com/sirupsen/logrus v0.0.0-20180213143110-8c0189d9f6bb/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= | ||||
| github.com/smartystreets/assertions v0.0.0-20180803164922-886ec427f6b9 h1:lXQ+j+KwZcbwrbgU0Rp4Eglg3EJLHbuZU3BbOqAGBmg= | ||||
| github.com/smartystreets/assertions v0.0.0-20180803164922-886ec427f6b9/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | ||||
| github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbmil4Ui/dDdFBExb7/cmkNjyX5F97oglmvCDo= | ||||
| github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | ||||
| github.com/spf13/afero v0.0.0-20180211162714-bbf41cb36dff h1:HLvGWId7M56TfuxTeZ6aoiTAcrWO5Mnq/ArwVRgV62I= | ||||
| github.com/spf13/afero v0.0.0-20180211162714-bbf41cb36dff/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= | ||||
| github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg= | ||||
| github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= | ||||
| github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec h1:2ZXvIUGghLpdTVHR1UfvfrzoVlZaE/yOWC5LueIHZig= | ||||
| github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= | ||||
| github.com/spf13/pflag v0.0.0-20180220143236-ee5fd03fd6ac h1:+uzyQ0TQ3aKorQxsOjcDDgE7CuUXwpkKnK19LULQALQ= | ||||
| github.com/spf13/pflag v0.0.0-20180220143236-ee5fd03fd6ac/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= | ||||
| github.com/spf13/viper v0.0.0-20171227194143-aafc9e6bc7b7 h1:Wj4cg2M6Um7j1N7yD/mxsdy1/wrsdjzVha2eWdOhti8= | ||||
| github.com/spf13/viper v0.0.0-20171227194143-aafc9e6bc7b7/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= | ||||
| github.com/stretchr/testify v0.0.0-20170714215325-05e8a0eda380 h1:MsolbevHkd4SpbeG4dHLHj6I9jzoohyNI6EK6JvR5hE= | ||||
| github.com/stretchr/testify v0.0.0-20170714215325-05e8a0eda380/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||
| github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= | ||||
| github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= | ||||
| github.com/valyala/bytebufferpool v0.0.0-20160817181652-e746df99fe4a h1:AOcehBWpFhYPYw0ioDTppQzgI8pAAahVCiMSKTp9rbo= | ||||
| github.com/valyala/bytebufferpool v0.0.0-20160817181652-e746df99fe4a/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= | ||||
| github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 h1:gKMu1Bf6QINDnvyZuTaACm9ofY+PRh+5vFz4oxBZeF8= | ||||
| github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4/go.mod h1:50wTf68f99/Zt14pr046Tgt3Lp2vLyFZKzbFXTOabXw= | ||||
| github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= | ||||
| github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= | ||||
| github.com/zfjagann/golang-ring v0.0.0-20141111230621-17637388c9f6 h1:/WULP+6asFz569UbOwg87f3iDT7T+GF5/vjLmL51Pdk= | ||||
| github.com/zfjagann/golang-ring v0.0.0-20141111230621-17637388c9f6/go.mod h1:0MsIttMJIF/8Y7x0XjonJP7K99t3sR6bjj4m5S4JmqU= | ||||
| golang.org/x/crypto v0.0.0-20180228161326-91a49db82a88 h1:jLkAo/qlT9whgCLYC5GAJ9kcKrv3Wj8VCc4N+KJ4wpw= | ||||
| golang.org/x/crypto v0.0.0-20180228161326-91a49db82a88/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/net v0.0.0-20180108090419-434ec0c7fe37 h1:BkNcmLtAVeWe9h5k0jt24CQgaG5vb4x/doFbAiEC/Ho= | ||||
| golang.org/x/net v0.0.0-20180108090419-434ec0c7fe37/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= | ||||
| golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sys v0.0.0-20171130163741-8b4580aae2a0 h1:x4M4WCms+ErQg/4VyECbP2kSNcDJ6nLwqEGov1QPtqk= | ||||
| golang.org/x/sys v0.0.0-20171130163741-8b4580aae2a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/text v0.0.0-20180511172408-5c1cf69b5978 h1:WNm0tmiuBMW4FJRuXKWOqaQfmKptHs0n8nTCyG0ayjc= | ||||
| golang.org/x/text v0.0.0-20180511172408-5c1cf69b5978/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||
| gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo= | ||||
| gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= | ||||
| gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= | ||||
| gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= | ||||
| gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | ||||
| gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.1 h1:4buh9nXkpqc7+GLzDFHei0jwoU9wCQYfVB5Kfo58Yz0= | ||||
| gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.1/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= | ||||
| gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= | ||||
| gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= | ||||
| gopkg.in/yaml.v2 v2.0.0-20160301204022-a83829b6f129 h1:RBgb9aPUbZ9nu66ecQNIBNsA7j3mB5h8PNDIfhPjaJg= | ||||
| gopkg.in/yaml.v2 v2.0.0-20160301204022-a83829b6f129/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= | ||||
							
								
								
									
										
											BIN
										
									
								
								img/matterbridge.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								img/matterbridge.gif
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 77 KiB | 
| @@ -3,24 +3,24 @@ package main | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/gateway" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	"github.com/google/gops/agent" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/gateway" | ||||
| 	"github.com/google/gops/agent" | ||||
| 	prefixed "github.com/matterbridge/logrus-prefixed-formatter" | ||||
| 	log "github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	version = "1.7.1" | ||||
| 	version = "1.11.2" | ||||
| 	githash string | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	log.SetFormatter(&log.TextFormatter{FullTimestamp: true}) | ||||
| } | ||||
|  | ||||
| func main() { | ||||
| 	log.SetFormatter(&prefixed.TextFormatter{PrefixPadding: 13, DisableColors: true, FullTimestamp: true}) | ||||
| 	flog := log.WithFields(log.Fields{"prefix": "main"}) | ||||
| 	flagConfig := flag.String("conf", "matterbridge.toml", "config file") | ||||
| 	flagDebug := flag.Bool("debug", false, "enable debug") | ||||
| 	flagVersion := flag.Bool("version", false, "show version") | ||||
| @@ -35,23 +35,24 @@ func main() { | ||||
| 		return | ||||
| 	} | ||||
| 	if *flagDebug || os.Getenv("DEBUG") == "1" { | ||||
| 		log.Info("Enabling debug") | ||||
| 		log.SetFormatter(&prefixed.TextFormatter{PrefixPadding: 13, DisableColors: true, FullTimestamp: false, ForceFormatting: true}) | ||||
| 		flog.Info("Enabling debug") | ||||
| 		log.SetLevel(log.DebugLevel) | ||||
| 	} | ||||
| 	log.Printf("Running version %s %s", version, githash) | ||||
| 	flog.Printf("Running version %s %s", version, githash) | ||||
| 	if strings.Contains(version, "-dev") { | ||||
| 		log.Println("WARNING: THIS IS A DEVELOPMENT VERSION. Things may break.") | ||||
| 		flog.Println("WARNING: THIS IS A DEVELOPMENT VERSION. Things may break.") | ||||
| 	} | ||||
| 	cfg := config.NewConfig(*flagConfig) | ||||
| 	cfg.General.Debug = *flagDebug | ||||
| 	r, err := gateway.NewRouter(cfg) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("Starting gateway failed: %s", err) | ||||
| 		flog.Fatalf("Starting gateway failed: %s", err) | ||||
| 	} | ||||
| 	err = r.Start() | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("Starting gateway failed: %s", err) | ||||
| 		flog.Fatalf("Starting gateway failed: %s", err) | ||||
| 	} | ||||
| 	log.Printf("Gateway(s) started succesfully. Now relaying messages") | ||||
| 	flog.Printf("Gateway(s) started succesfully. Now relaying messages") | ||||
| 	select {} | ||||
| } | ||||
|   | ||||
| @@ -64,6 +64,9 @@ NickServPassword="secret" | ||||
| #OPTIONAL only used for quakenet auth | ||||
| NickServUsername="username" | ||||
|  | ||||
| ## RELOADABLE SETTINGS | ||||
| ## Settings below can be reloaded by editing the file | ||||
|  | ||||
| #Flood control | ||||
| #Delay in milliseconds between each message send to the IRC server | ||||
| #OPTIONAL (default 1300) | ||||
| @@ -89,6 +92,10 @@ MessageSplit=false | ||||
| #OPTIONAL (default 0) | ||||
| RejoinDelay=0 | ||||
|  | ||||
| #ColorNicks will show each nickname in a different color. | ||||
| #Only works in IRC right now. | ||||
| ColorNicks=false | ||||
|  | ||||
| #Nicks you want to ignore.  | ||||
| #Messages from those users will not be sent to other bridges. | ||||
| #OPTIONAL | ||||
| @@ -117,24 +124,39 @@ ReplaceMessages=[ ["cat","dog"] ] | ||||
| #optional (default empty) | ||||
| ReplaceNicks=[ ["user--","user"] ] | ||||
|  | ||||
| #extra label that can be used in the RemoteNickFormat | ||||
| #optional (default empty) | ||||
| Label="" | ||||
|  | ||||
| #RemoteNickFormat defines how remote users appear on this bridge  | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| #The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge | ||||
| #The string "{NOPINGNICK}" (case sensitive) will be replaced by the actual nick / username, but with a ZWSP inside the nick, so the irc user with the same nick won't get pinged. See https://github.com/42wim/matterbridge/issues/175 for more information | ||||
| #OPTIONAL (default empty) | ||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||
|  | ||||
| #Enable to show users joins/parts from other bridges  | ||||
| #Only works hiding/show messages from irc and mattermost bridge for now | ||||
| #Currently works for messages from the following bridges: irc, mattermost, slack | ||||
| #OPTIONAL (default false) | ||||
| ShowJoinPart=false | ||||
|  | ||||
| #Do not send joins/parts to other bridges | ||||
| #Currently works for messages from the following bridges: irc, mattermost, slack | ||||
| #OPTIONAL (default false) | ||||
| NoSendJoinPart=false | ||||
|  | ||||
| #StripNick only allows alphanumerical nicks. See https://github.com/42wim/matterbridge/issues/285 | ||||
| #It will strip other characters from the nick | ||||
| #OPTIONAL (default false) | ||||
| StripNick=false | ||||
|  | ||||
| #Enable to show topic changes from other bridges  | ||||
| #Only works hiding/show topic changes from slack bridge for now | ||||
| #OPTIONAL (default false) | ||||
| ShowTopicChange=false | ||||
|  | ||||
| ################################################################### | ||||
| #XMPP section | ||||
| ################################################################### | ||||
| @@ -169,6 +191,9 @@ Nick="xmppbot" | ||||
| #OPTIONAL (default false) | ||||
| SkipTLSVerify=true | ||||
|  | ||||
| ## RELOADABLE SETTINGS | ||||
| ## Settings below can be reloaded by editing the file | ||||
|  | ||||
| #Nicks you want to ignore.  | ||||
| #Messages from those users will not be sent to other bridges. | ||||
| #OPTIONAL | ||||
| @@ -197,15 +222,20 @@ ReplaceMessages=[ ["cat","dog"] ] | ||||
| #OPTIONAL (default empty) | ||||
| ReplaceNicks=[ ["user--","user"] ] | ||||
|  | ||||
| #extra label that can be used in the RemoteNickFormat | ||||
| #optional (default empty) | ||||
| Label="" | ||||
|  | ||||
| #RemoteNickFormat defines how remote users appear on this bridge  | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| #The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge | ||||
| #OPTIONAL (default empty) | ||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||
|  | ||||
| #Enable to show users joins/parts from other bridges  | ||||
| #Only works hiding/show messages from irc and mattermost bridge for now | ||||
| #Currently works for messages from the following bridges: irc, mattermost, slack | ||||
| #OPTIONAL (default false) | ||||
| ShowJoinPart=false | ||||
|  | ||||
| @@ -214,6 +244,11 @@ ShowJoinPart=false | ||||
| #OPTIONAL (default false) | ||||
| StripNick=false | ||||
|  | ||||
| #Enable to show topic changes from other bridges  | ||||
| #Only works hiding/show topic changes from slack bridge for now | ||||
| #OPTIONAL (default false) | ||||
| ShowTopicChange=false | ||||
|  | ||||
| ################################################################### | ||||
| #hipchat section | ||||
| ################################################################### | ||||
| @@ -240,6 +275,9 @@ Muc="conf.hipchat.com" | ||||
| #REQUIRED | ||||
| Nick="yourlogin" | ||||
|  | ||||
| ## RELOADABLE SETTINGS | ||||
| ## Settings below can be reloaded by editing the file | ||||
|  | ||||
| #Nicks you want to ignore.  | ||||
| #Messages from those users will not be sent to other bridges. | ||||
| #OPTIONAL | ||||
| @@ -268,15 +306,20 @@ ReplaceMessages=[ ["cat","dog"] ] | ||||
| #optional (default empty) | ||||
| ReplaceNicks=[ ["user--","user"] ] | ||||
|  | ||||
| #extra label that can be used in the RemoteNickFormat | ||||
| #optional (default empty) | ||||
| Label="" | ||||
|  | ||||
| #RemoteNickFormat defines how remote users appear on this bridge  | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| #The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge | ||||
| #OPTIONAL (default empty) | ||||
| RemoteNickFormat="[{PROTOCOL}/{BRIDGE}] <{NICK}> " | ||||
|  | ||||
| #Enable to show users joins/parts from other bridges  | ||||
| #Only works hiding/show messages from irc and mattermost bridge for now | ||||
| #Currently works for messages from the following bridges: irc, mattermost, slack | ||||
| #OPTIONAL (default false) | ||||
| ShowJoinPart=false | ||||
|  | ||||
| @@ -285,6 +328,11 @@ ShowJoinPart=false | ||||
| #OPTIONAL (default false) | ||||
| StripNick=false | ||||
|  | ||||
| #Enable to show topic changes from other bridges  | ||||
| #Only works hiding/show topic changes from slack bridge for now | ||||
| #OPTIONAL (default false) | ||||
| ShowTopicChange=false | ||||
|  | ||||
| ################################################################### | ||||
| #mattermost section | ||||
| ################################################################### | ||||
| @@ -347,6 +395,9 @@ IconURL="http://youricon.png" | ||||
| #OPTIONAL (default false) | ||||
| SkipTLSVerify=true | ||||
|  | ||||
| ## RELOADABLE SETTINGS | ||||
| ## Settings below can be reloaded by editing the file | ||||
|  | ||||
| #how to format the list of IRC nicks when displayed in mattermost.  | ||||
| #Possible options are "table" and "plain" | ||||
| #OPTIONAL (default plain) | ||||
| @@ -399,23 +450,38 @@ ReplaceMessages=[ ["cat","dog"] ] | ||||
| #optional (default empty) | ||||
| ReplaceNicks=[ ["user--","user"] ] | ||||
|  | ||||
| #extra label that can be used in the RemoteNickFormat | ||||
| #optional (default empty) | ||||
| Label="" | ||||
|  | ||||
| #RemoteNickFormat defines how remote users appear on this bridge  | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| #The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge | ||||
| #OPTIONAL (default empty) | ||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||
|  | ||||
| #Enable to show users joins/parts from other bridges  | ||||
| #Only works hiding/show messages from irc and mattermost bridge for now | ||||
| #Currently works for messages from the following bridges: irc, mattermost, slack | ||||
| #OPTIONAL (default false) | ||||
| ShowJoinPart=false | ||||
|  | ||||
| #Do not send joins/parts to other bridges | ||||
| #Currently works for messages from the following bridges: irc, mattermost, slack | ||||
| #OPTIONAL (default false) | ||||
| NoSendJoinPart=false | ||||
|  | ||||
| #StripNick only allows alphanumerical nicks. See https://github.com/42wim/matterbridge/issues/285 | ||||
| #It will strip other characters from the nick | ||||
| #OPTIONAL (default false) | ||||
| StripNick=false | ||||
|  | ||||
| #Enable to show topic changes from other bridges  | ||||
| #Only works hiding/show topic changes from slack bridge for now | ||||
| #OPTIONAL (default false) | ||||
| ShowTopicChange=false | ||||
|  | ||||
| ################################################################### | ||||
| #Gitter section | ||||
| #Best to make a dedicated gitter account for the bot. | ||||
| @@ -432,6 +498,9 @@ StripNick=false | ||||
| #REQUIRED | ||||
| Token="Yourtokenhere" | ||||
|  | ||||
| ## RELOADABLE SETTINGS | ||||
| ## Settings below can be reloaded by editing the file | ||||
|  | ||||
| #Nicks you want to ignore.  | ||||
| #Messages from those users will not be sent to other bridges. | ||||
| #OPTIONAL | ||||
| @@ -460,15 +529,20 @@ ReplaceMessages=[ ["cat","dog"] ] | ||||
| #optional (default empty) | ||||
| ReplaceNicks=[ ["user--","user"] ] | ||||
|  | ||||
| #extra label that can be used in the RemoteNickFormat | ||||
| #optional (default empty) | ||||
| Label="" | ||||
|  | ||||
| #RemoteNickFormat defines how remote users appear on this bridge  | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| #The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge | ||||
| #OPTIONAL (default empty) | ||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||
|  | ||||
| #Enable to show users joins/parts from other bridges  | ||||
| #Only works hiding/show messages from irc and mattermost bridge for now | ||||
| #Currently works for messages from the following bridges: irc, mattermost, slack | ||||
| #OPTIONAL (default false) | ||||
| ShowJoinPart=false | ||||
|  | ||||
| @@ -477,6 +551,11 @@ ShowJoinPart=false | ||||
| #OPTIONAL (default false) | ||||
| StripNick=false | ||||
|  | ||||
| #Enable to show topic changes from other bridges  | ||||
| #Only works hiding/show topic changes from slack bridge for now | ||||
| #OPTIONAL (default false) | ||||
| ShowTopicChange=false | ||||
|  | ||||
| ################################################################### | ||||
| #slack section | ||||
| ################################################################### | ||||
| @@ -512,10 +591,14 @@ WebhookBindAddress="0.0.0.0:9999" | ||||
| #Icon that will be showed in slack | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| #The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge | ||||
| #OPTIONAL | ||||
| IconURL="https://robohash.org/{NICK}.png?size=48x48" | ||||
|  | ||||
| ## RELOADABLE SETTINGS | ||||
| ## Settings below can be reloaded by editing the file | ||||
|  | ||||
| #how to format the list of IRC nicks when displayed in slack | ||||
| #Possible options are "table" and "plain" | ||||
| #OPTIONAL (default plain) | ||||
| @@ -568,23 +651,38 @@ ReplaceMessages=[ ["cat","dog"] ] | ||||
| #optional (default empty) | ||||
| ReplaceNicks=[ ["user--","user"] ] | ||||
|  | ||||
| #extra label that can be used in the RemoteNickFormat | ||||
| #optional (default empty) | ||||
| Label="" | ||||
|  | ||||
| #RemoteNickFormat defines how remote users appear on this bridge  | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| #The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge | ||||
| #OPTIONAL (default empty) | ||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||
|  | ||||
| #Enable to show users joins/parts from other bridges  | ||||
| #Only works hiding/show messages from irc and mattermost bridge for now | ||||
| #Currently works for messages from the following bridges: irc, mattermost, slack | ||||
| #OPTIONAL (default false) | ||||
| ShowJoinPart=false | ||||
|  | ||||
| #Do not send joins/parts to other bridges | ||||
| #Currently works for messages from the following bridges: irc, mattermost, slack | ||||
| #OPTIONAL (default false) | ||||
| NoSendJoinPart=false | ||||
|  | ||||
| #StripNick only allows alphanumerical nicks. See https://github.com/42wim/matterbridge/issues/285 | ||||
| #It will strip other characters from the nick | ||||
| #OPTIONAL (default false) | ||||
| StripNick=false | ||||
|  | ||||
| #Enable to show topic changes from other bridges  | ||||
| #Only works hiding/show topic changes from slack bridge for now | ||||
| #OPTIONAL (default false) | ||||
| ShowTopicChange=false | ||||
|  | ||||
| ################################################################### | ||||
| #discord section | ||||
| ################################################################### | ||||
| @@ -604,6 +702,9 @@ Token="Yourtokenhere" | ||||
| #REQUIRED | ||||
| Server="yourservername" | ||||
|  | ||||
| ## RELOADABLE SETTINGS | ||||
| ## Settings below can be reloaded by editing the file | ||||
|  | ||||
| #Shows title, description and URL of embedded messages (sent by other bots) | ||||
| #OPTIONAL (default false) | ||||
| ShowEmbeds=false | ||||
| @@ -653,15 +754,20 @@ ReplaceMessages=[ ["cat","dog"] ] | ||||
| #optional (default empty) | ||||
| ReplaceNicks=[ ["user--","user"] ] | ||||
|  | ||||
| #extra label that can be used in the RemoteNickFormat | ||||
| #optional (default empty) | ||||
| Label="" | ||||
|  | ||||
| #RemoteNickFormat defines how remote users appear on this bridge  | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| #The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge | ||||
| #OPTIONAL (default empty) | ||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||
|  | ||||
| #Enable to show users joins/parts from other bridges  | ||||
| #Only works hiding/show messages from irc and mattermost bridge for now | ||||
| #Currently works for messages from the following bridges: irc, mattermost, slack | ||||
| #OPTIONAL (default false) | ||||
| ShowJoinPart=false | ||||
|  | ||||
| @@ -670,6 +776,11 @@ ShowJoinPart=false | ||||
| #OPTIONAL (default false) | ||||
| StripNick=false | ||||
|  | ||||
| #Enable to show topic changes from other bridges  | ||||
| #Only works hiding/show topic changes from slack bridge for now | ||||
| #OPTIONAL (default false) | ||||
| ShowTopicChange=false | ||||
|  | ||||
| ################################################################### | ||||
| #telegram section | ||||
| ################################################################### | ||||
| @@ -684,9 +795,14 @@ StripNick=false | ||||
| #REQUIRED | ||||
| Token="Yourtokenhere" | ||||
|  | ||||
| ## RELOADABLE SETTINGS | ||||
| ## Settings below can be reloaded by editing the file | ||||
|  | ||||
| #OPTIONAL (default empty) | ||||
| #Only supported format is "HTML", messages will be sent in html parsemode. | ||||
| #Supported formats are "HTML", "Markdown" and "HTMLNick" | ||||
| #See https://core.telegram.org/bots/api#html-style | ||||
| #See https://core.telegram.org/bots/api#markdown-style | ||||
| #HTMLNick only allows HTML for the nick, the message itself will be html-escaped | ||||
| MessageFormat="" | ||||
|  | ||||
| #If enabled use the "First Name" as username. If this is empty use the Username | ||||
| @@ -701,6 +817,14 @@ UseFirstName=false | ||||
| #OPTIONAL (default false) | ||||
| UseInsecureURL=false | ||||
|  | ||||
| #Disable quoted/reply messages | ||||
| #OPTIONAL (default false) | ||||
| QuoteDisable=false | ||||
|  | ||||
| #Format quoted/reply messages | ||||
| #OPTIONAL (default "{MESSAGE} (re @{QUOTENICK}: {QUOTEMESSAGE})") | ||||
| QuoteFormat="{MESSAGE} (re @{QUOTENICK}: {QUOTEMESSAGE})" | ||||
|  | ||||
| #Disable sending of edits to other bridges | ||||
| #OPTIONAL (default false) | ||||
| EditDisable=false | ||||
| @@ -737,15 +861,25 @@ ReplaceMessages=[ ["cat","dog"] ] | ||||
| #optional (default empty) | ||||
| ReplaceNicks=[ ["user--","user"] ] | ||||
|  | ||||
| #extra label that can be used in the RemoteNickFormat | ||||
| #optional (default empty) | ||||
| Label="" | ||||
|  | ||||
| #RemoteNickFormat defines how remote users appear on this bridge  | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| #The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge | ||||
| # | ||||
| #WARNING: if you have set MessageFormat="HTML" be sure that this format matches the guidelines | ||||
| #on https://core.telegram.org/bots/api#html-style otherwise the message will not go through to | ||||
| #telegram! eg <{NICK}> should be <{NICK}> | ||||
| # | ||||
| #OPTIONAL (default empty) | ||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||
|  | ||||
| #Enable to show users joins/parts from other bridges  | ||||
| #Only works hiding/show messages from irc and mattermost bridge for now | ||||
| #Currently works for messages from the following bridges: irc, mattermost, slack | ||||
| #OPTIONAL (default false) | ||||
| ShowJoinPart=false | ||||
|  | ||||
| @@ -754,6 +888,11 @@ ShowJoinPart=false | ||||
| #OPTIONAL (default false) | ||||
| StripNick=false | ||||
|  | ||||
| #Enable to show topic changes from other bridges  | ||||
| #Only works hiding/show topic changes from slack bridge for now | ||||
| #OPTIONAL (default false) | ||||
| ShowTopicChange=false | ||||
|  | ||||
| ################################################################### | ||||
| #rocketchat section | ||||
| ################################################################### | ||||
| @@ -787,6 +926,9 @@ NoTLS=false | ||||
| #OPTIONAL (default false) | ||||
| SkipTLSVerify=true | ||||
|  | ||||
| ## RELOADABLE SETTINGS | ||||
| ## Settings below can be reloaded by editing the file | ||||
|  | ||||
| #Whether to prefix messages from other bridges to rocketchat with the sender's nick.  | ||||
| #Useful if username overrides for incoming webhooks isn't enabled on the  | ||||
| #rocketchat server. If you set PrefixMessagesWithNick to true, each message  | ||||
| @@ -822,15 +964,20 @@ ReplaceMessages=[ ["cat","dog"] ] | ||||
| #optional (default empty) | ||||
| ReplaceNicks=[ ["user--","user"] ] | ||||
|  | ||||
| #extra label that can be used in the RemoteNickFormat | ||||
| #optional (default empty) | ||||
| Label="" | ||||
|  | ||||
| #RemoteNickFormat defines how remote users appear on this bridge  | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| #The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge | ||||
| #OPTIONAL (default empty) | ||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||
|  | ||||
| #Enable to show users joins/parts from other bridges  | ||||
| #Only works hiding/show messages from irc and mattermost bridge for now | ||||
| #Currently works for messages from the following bridges: irc, mattermost, slack | ||||
| #OPTIONAL (default false) | ||||
| ShowJoinPart=false | ||||
|  | ||||
| @@ -839,6 +986,11 @@ ShowJoinPart=false | ||||
| #OPTIONAL (default false) | ||||
| StripNick=false | ||||
|  | ||||
| #Enable to show topic changes from other bridges  | ||||
| #Only works hiding/show topic changes from slack bridge for now | ||||
| #OPTIONAL (default false) | ||||
| ShowTopicChange=false | ||||
|  | ||||
| ################################################################### | ||||
| #matrix section | ||||
| ################################################################### | ||||
| @@ -864,6 +1016,9 @@ Password="yourpass" | ||||
| #OPTIONAL (default false) | ||||
| NoHomeServerSuffix=false | ||||
|  | ||||
| ## RELOADABLE SETTINGS | ||||
| ## Settings below can be reloaded by editing the file | ||||
|  | ||||
| #Whether to prefix messages from other bridges to matrix with the sender's nick.  | ||||
| #Useful if username overrides for incoming webhooks isn't enabled on the  | ||||
| #matrix server. If you set PrefixMessagesWithNick to true, each message  | ||||
| @@ -899,15 +1054,20 @@ ReplaceMessages=[ ["cat","dog"] ] | ||||
| #optional (default empty) | ||||
| ReplaceNicks=[ ["user--","user"] ] | ||||
|  | ||||
| #extra label that can be used in the RemoteNickFormat | ||||
| #optional (default empty) | ||||
| Label="" | ||||
|  | ||||
| #RemoteNickFormat defines how remote users appear on this bridge  | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| #The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge | ||||
| #OPTIONAL (default empty) | ||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||
|  | ||||
| #Enable to show users joins/parts from other bridges  | ||||
| #Only works hiding/show messages from irc and mattermost bridge for now | ||||
| #Currently works for messages from the following bridges: irc, mattermost, slack | ||||
| #OPTIONAL (default false) | ||||
| ShowJoinPart=false | ||||
|  | ||||
| @@ -916,6 +1076,11 @@ ShowJoinPart=false | ||||
| #OPTIONAL (default false) | ||||
| StripNick=false | ||||
|  | ||||
| #Enable to show topic changes from other bridges  | ||||
| #Only works hiding/show topic changes from slack bridge for now | ||||
| #OPTIONAL (default false) | ||||
| ShowTopicChange=false | ||||
|  | ||||
| ################################################################### | ||||
| #steam section | ||||
| ################################################################### | ||||
| @@ -935,6 +1100,9 @@ Password="yourpass" | ||||
| #OPTIONAL  | ||||
| Authcode="ABCE12" | ||||
|  | ||||
| ## RELOADABLE SETTINGS | ||||
| ## Settings below can be reloaded by editing the file | ||||
|  | ||||
| #Whether to prefix messages from other bridges to matrix with the sender's nick.  | ||||
| #Useful if username overrides for incoming webhooks isn't enabled on the  | ||||
| #matrix server. If you set PrefixMessagesWithNick to true, each message  | ||||
| @@ -970,15 +1138,20 @@ ReplaceMessages=[ ["cat","dog"] ] | ||||
| #optional (default empty) | ||||
| ReplaceNicks=[ ["user--","user"] ] | ||||
|  | ||||
| #extra label that can be used in the RemoteNickFormat | ||||
| #optional (default empty) | ||||
| Label="" | ||||
|  | ||||
| #RemoteNickFormat defines how remote users appear on this bridge  | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| #The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge | ||||
| #OPTIONAL (default empty) | ||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||
|  | ||||
| #Enable to show users joins/parts from other bridges  | ||||
| #Only works hiding/show messages from irc and mattermost bridge for now | ||||
| #Currently works for messages from the following bridges: irc, mattermost, slack | ||||
| #OPTIONAL (default false) | ||||
| ShowJoinPart=false | ||||
|  | ||||
| @@ -987,6 +1160,95 @@ ShowJoinPart=false | ||||
| #OPTIONAL (default false) | ||||
| StripNick=false | ||||
|  | ||||
| #Enable to show topic changes from other bridges  | ||||
| #Only works hiding/show topic changes from slack bridge for now | ||||
| #OPTIONAL (default false) | ||||
| ShowTopicChange=false | ||||
|  | ||||
| ################################################################### | ||||
| #zulip section | ||||
| ################################################################### | ||||
| [zulip] | ||||
| #You can configure multiple servers "[zulip.name]" or "[zulip.name2]" | ||||
| #In this example we use [zulip.streamchat] | ||||
| #REQUIRED | ||||
|  | ||||
| [zulip.streamchat] | ||||
| #Token to connect with zulip API (called bot API key in Settings - Your bots) | ||||
| #REQUIRED | ||||
| Token="Yourtokenhere" | ||||
|  | ||||
| #Username of the bot, normally called yourbot-bot@yourserver.zulipchat.com  | ||||
| #See username in Settings - Your bots  | ||||
| #REQUIRED | ||||
| Login="yourbot-bot@yourserver.zulipchat.com" | ||||
|  | ||||
| #Servername of your zulip instance | ||||
| #REQUIRED  | ||||
| Server="https://yourserver.zulipchat.com" | ||||
|  | ||||
| #Topic of the messages matterbridge will use | ||||
| #OPTIONAL (default "matterbridge") | ||||
| Topic="matterbridge" | ||||
|  | ||||
| ## RELOADABLE SETTINGS | ||||
| ## Settings below can be reloaded by editing the file | ||||
|  | ||||
| #Nicks you want to ignore.  | ||||
| #Messages from those users will not be sent to other bridges. | ||||
| #OPTIONAL | ||||
| IgnoreNicks="spammer1 spammer2" | ||||
|  | ||||
| #Messages you want to ignore.  | ||||
| #Messages matching these regexp will be ignored and not sent to other bridges | ||||
| #See https://regex-golang.appspot.com/assets/html/index.html for more regex info | ||||
| #OPTIONAL (example below ignores messages starting with ~~ or messages containing badword | ||||
| IgnoreMessages="^~~ badword" | ||||
|  | ||||
| #messages you want to replace. | ||||
| #it replaces outgoing messages from the bridge. | ||||
| #so you need to place it by the sending bridge definition. | ||||
| #regular expressions supported | ||||
| #some examples: | ||||
| #this replaces cat => dog and sleep => awake | ||||
| #replacemessages=[ ["cat","dog"], ["sleep","awake"] ] | ||||
| #this replaces every number with number.  123 => numbernumbernumber | ||||
| #replacemessages=[ ["[0-9]","number"] ] | ||||
| #optional (default empty) | ||||
| ReplaceMessages=[ ["cat","dog"] ] | ||||
|  | ||||
| #nicks you want to replace. | ||||
| #see replacemessages for syntaxa | ||||
| #optional (default empty) | ||||
| ReplaceNicks=[ ["user--","user"] ] | ||||
|  | ||||
| #extra label that can be used in the RemoteNickFormat | ||||
| #optional (default empty) | ||||
| Label="" | ||||
|  | ||||
| #RemoteNickFormat defines how remote users appear on this bridge  | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| #The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge | ||||
| #OPTIONAL (default empty) | ||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||
|  | ||||
| #Enable to show users joins/parts from other bridges  | ||||
| #Currently works for messages from the following bridges: irc, mattermost, slack | ||||
| #OPTIONAL (default false) | ||||
| ShowJoinPart=false | ||||
|  | ||||
| #StripNick only allows alphanumerical nicks. See https://github.com/42wim/matterbridge/issues/285 | ||||
| #It will strip other characters from the nick | ||||
| #OPTIONAL (default false) | ||||
| StripNick=false | ||||
|  | ||||
| #Enable to show topic changes from other bridges  | ||||
| #Only works hiding/show topic changes from slack bridge for now | ||||
| #OPTIONAL (default false) | ||||
| ShowTopicChange=false | ||||
|  | ||||
| ################################################################### | ||||
| #API | ||||
| ################################################################### | ||||
| @@ -1008,9 +1270,14 @@ Buffer=1000 | ||||
| #OPTIONAL (no authorization if token is empty) | ||||
| Token="mytoken" | ||||
|  | ||||
| #extra label that can be used in the RemoteNickFormat | ||||
| #optional (default empty) | ||||
| Label="" | ||||
|  | ||||
| #RemoteNickFormat defines how remote users appear on this bridge  | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| #The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge | ||||
| #OPTIONAL (default empty) | ||||
| RemoteNickFormat="{NICK}" | ||||
| @@ -1022,9 +1289,14 @@ RemoteNickFormat="{NICK}" | ||||
| ################################################################### | ||||
| # Settings here are defaults that each protocol can override | ||||
| [general] | ||||
|  | ||||
| ## RELOADABLE SETTINGS | ||||
| ## Settings below can be reloaded by editing the file | ||||
|  | ||||
| #RemoteNickFormat defines how remote users appear on this bridge  | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick / username. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| #The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge | ||||
| #OPTIONAL (default empty) | ||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||
| @@ -1035,10 +1307,13 @@ RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||
| StripNick=false | ||||
|  | ||||
|  | ||||
| #MediaServerUpload and MediaServerDownload are used for uploading images/files/video to | ||||
| #a remote "mediaserver" (a webserver like caddy for example). | ||||
| #When configured images/files uploaded on bridges like mattermost,slack, telegram will be downloaded | ||||
| #and uploaded again to MediaServerUpload URL | ||||
| #MediaServerUpload (or MediaDownloadPath) and MediaServerDownload are used for uploading | ||||
| #images/files/video to a remote "mediaserver" (a webserver like caddy for example). | ||||
| #When configured images/files uploaded on bridges like mattermost, slack, telegram will be | ||||
| #downloaded and uploaded again to MediaServerUpload URL | ||||
| #MediaDownloadPath is the filesystem path where the media file will be placed, instead of uploaded, | ||||
| #for if Matterbridge has write access to the directory your webserver is serving. | ||||
| #It is an alternative to MediaServerUpload. | ||||
| #The MediaServerDownload will be used so that bridges without native uploading support: | ||||
| #gitter, irc and xmpp will be shown links to the files on MediaServerDownload | ||||
| # | ||||
| @@ -1046,6 +1321,8 @@ StripNick=false | ||||
| #OPTIONAL (default empty) | ||||
| MediaServerUpload="https://user:pass@yourserver.com/upload" | ||||
| #OPTIONAL (default empty) | ||||
| MediaDownloadPath="/srv/http/yourserver.com/public/download" | ||||
| #OPTIONAL (default empty) | ||||
| MediaServerDownload="https://youserver.com/download" | ||||
|  | ||||
| #MediaDownloadSize is the maximum size of attachments, videos, images | ||||
| @@ -1053,11 +1330,17 @@ MediaServerDownload="https://youserver.com/download" | ||||
| #eg downloading from slack to upload it to mattermost | ||||
| # | ||||
| #It will only download from bridges that don't have public links available, which are for the moment | ||||
| #slack, telegram and matrix | ||||
| #slack, telegram, matrix and mattermost | ||||
| # | ||||
| #Optional (default 1000000 (1 megabyte)) | ||||
| #OPTIONAL (default 1000000 (1 megabyte)) | ||||
| MediaDownloadSize=1000000 | ||||
|  | ||||
| #MediaDownloadBlacklist allows you to blacklist specific files from being downloaded. | ||||
| #Filenames matching these regexp will not be download/uploaded to the mediaserver | ||||
| #You can use regex for this, see https://regex-golang.appspot.com/assets/html/index.html for more regex info | ||||
| #OPTIONAL (default empty) | ||||
| MediaDownloadBlacklist=[".html$",".htm$"] | ||||
|  | ||||
| ################################################################### | ||||
| #Gateway configuration | ||||
| ################################################################### | ||||
| @@ -1094,6 +1377,7 @@ enable=true | ||||
|     #gitter     - username/room  | ||||
|     #xmpp       - channel | ||||
|     #slack      - channel (without the #) | ||||
|     #           - ID:C123456 (where C123456 is the channel ID) does not work with webhook | ||||
|     #discord    - channel (without the #) | ||||
|     #           - ID:123456789 (where 123456789 is the channel ID)  | ||||
|     #               (https://github.com/42wim/matterbridge/issues/57) | ||||
| @@ -1105,13 +1389,14 @@ enable=true | ||||
|     #           - encrypted rooms are not supported in matrix | ||||
|     #steam      - chatid (a large number).  | ||||
|     #             The number in the URL when you click "enter chat room" in the browser | ||||
|     #zulip      - stream (without the #) | ||||
|     #                   | ||||
|     #REQUIRED | ||||
|     channel="#testing" | ||||
|  | ||||
|         #OPTIONAL - only used for IRC protocol at the moment | ||||
|         #OPTIONAL - only used for IRC and XMPP protocols at the moment | ||||
|         [gateway.in.options] | ||||
|         #OPTIONAL - your irc channel key | ||||
|         #OPTIONAL - your irc / xmpp channel key | ||||
|         key="yourkey" | ||||
|  | ||||
|  | ||||
| @@ -1120,9 +1405,9 @@ enable=true | ||||
|     account="irc.freenode" | ||||
|     channel="#testing" | ||||
|  | ||||
|         #OPTIONAL - only used for IRC protocol at the moment | ||||
|         #OPTIONAL - only used for IRC and XMPP protocols at the moment | ||||
|         [gateway.out.options] | ||||
|         #OPTIONAL - your irc channel key | ||||
|         #OPTIONAL - your irc / xmpp channel key | ||||
|         key="yourkey" | ||||
|  | ||||
|     #[[gateway.inout]] can be used when then channel will be used to receive from  | ||||
| @@ -1131,9 +1416,9 @@ enable=true | ||||
|     account="mattermost.work" | ||||
|     channel="off-topic" | ||||
|  | ||||
|         #OPTIONAL - only used for IRC protocol at the moment | ||||
|         #OPTIONAL - only used for IRC and XMPP protocols at the moment | ||||
|         [gateway.inout.options] | ||||
|         #OPTIONAL - your irc channel key | ||||
|         #OPTIONAL - your irc / xmpp channel key | ||||
|         key="yourkey" | ||||
|  | ||||
|     [[gateway.inout]] | ||||
|   | ||||
| @@ -13,7 +13,8 @@ import ( | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	prefixed "github.com/matterbridge/logrus-prefixed-formatter" | ||||
| 	log "github.com/sirupsen/logrus" | ||||
|  | ||||
| 	"github.com/gorilla/websocket" | ||||
| 	"github.com/hashicorp/golang-lru" | ||||
| @@ -73,12 +74,16 @@ type MMClient struct { | ||||
| func New(login, pass, team, server string) *MMClient { | ||||
| 	cred := &Credentials{Login: login, Pass: pass, Team: team, Server: server} | ||||
| 	mmclient := &MMClient{Credentials: cred, MessageChan: make(chan *Message, 100), Users: make(map[string]*model.User)} | ||||
| 	mmclient.log = log.WithFields(log.Fields{"module": "matterclient"}) | ||||
| 	log.SetFormatter(&log.TextFormatter{FullTimestamp: true}) | ||||
| 	log.SetFormatter(&prefixed.TextFormatter{PrefixPadding: 13, DisableColors: true}) | ||||
| 	mmclient.log = log.WithFields(log.Fields{"prefix": "matterclient"}) | ||||
| 	mmclient.lruCache, _ = lru.New(500) | ||||
| 	return mmclient | ||||
| } | ||||
|  | ||||
| func (m *MMClient) SetDebugLog() { | ||||
| 	log.SetFormatter(&prefixed.TextFormatter{PrefixPadding: 13, DisableColors: true, FullTimestamp: false, ForceFormatting: true}) | ||||
| } | ||||
|  | ||||
| func (m *MMClient) SetLogLevel(level string) { | ||||
| 	l, err := log.ParseLevel(level) | ||||
| 	if err != nil { | ||||
| @@ -185,7 +190,11 @@ func (m *MMClient) Login() error { | ||||
| 	} | ||||
|  | ||||
| 	if m.Team == nil { | ||||
| 		return errors.New("team not found") | ||||
| 		validTeamNames := make([]string, len(m.OtherTeams)) | ||||
| 		for i, t := range m.OtherTeams { | ||||
| 			validTeamNames[i] = t.Team.Name | ||||
| 		} | ||||
| 		return fmt.Errorf("Team '%s' not found in %v", m.Credentials.Team, validTeamNames) | ||||
| 	} | ||||
|  | ||||
| 	m.wsConnect() | ||||
| @@ -301,6 +310,11 @@ func (m *MMClient) parseMessage(rmsg *Message) { | ||||
| 	switch rmsg.Raw.Event { | ||||
| 	case model.WEBSOCKET_EVENT_POSTED, model.WEBSOCKET_EVENT_POST_EDITED, model.WEBSOCKET_EVENT_POST_DELETED: | ||||
| 		m.parseActionPost(rmsg) | ||||
| 	case "user_updated": | ||||
| 		user := rmsg.Raw.Data["user"].(map[string]interface{}) | ||||
| 		if _, ok := user["id"].(string); ok { | ||||
| 			m.UpdateUser(user["id"].(string)) | ||||
| 		} | ||||
| 		/* | ||||
| 			case model.ACTION_USER_REMOVED: | ||||
| 				m.handleWsActionUserRemoved(&rmsg) | ||||
| @@ -565,7 +579,7 @@ func (m *MMClient) GetFileLinks(filenames []string) []string { | ||||
| 		res, resp := m.Client.GetFileLink(f) | ||||
| 		if resp.Error != nil { | ||||
| 			// public links is probably disabled, create the link ourselves | ||||
| 			output = append(output, uriScheme+m.Credentials.Server+model.API_URL_SUFFIX_V3+"/files/"+f+"/get") | ||||
| 			output = append(output, uriScheme+m.Credentials.Server+model.API_URL_SUFFIX_V4+"/files/"+f) | ||||
| 			continue | ||||
| 		} | ||||
| 		output = append(output, res) | ||||
| @@ -585,9 +599,9 @@ func (m *MMClient) UpdateChannelHeader(channelId string, header string) { | ||||
| func (m *MMClient) UpdateLastViewed(channelId string) { | ||||
| 	m.log.Debugf("posting lastview %#v", channelId) | ||||
| 	view := &model.ChannelView{ChannelId: channelId} | ||||
| 	res, _ := m.Client.ViewChannel(m.User.Id, view) | ||||
| 	if !res { | ||||
| 		m.log.Errorf("ChannelView update for %s failed", channelId) | ||||
| 	_, resp := m.Client.ViewChannel(m.User.Id, view) | ||||
| 	if resp.Error != nil { | ||||
| 		m.log.Errorf("ChannelView update for %s failed: %s", channelId, resp.Error) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -741,6 +755,16 @@ func (m *MMClient) GetUser(userId string) *model.User { | ||||
| 	return m.Users[userId] | ||||
| } | ||||
|  | ||||
| func (m *MMClient) UpdateUser(userId string) { | ||||
| 	m.Lock() | ||||
| 	defer m.Unlock() | ||||
| 	res, resp := m.Client.GetUser(userId, "") | ||||
| 	if resp.Error != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	m.Users[userId] = res | ||||
| } | ||||
|  | ||||
| func (m *MMClient) GetUserName(userId string) string { | ||||
| 	user := m.GetUser(userId) | ||||
| 	if user != nil { | ||||
| @@ -749,6 +773,14 @@ func (m *MMClient) GetUserName(userId string) string { | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *MMClient) GetNickName(userId string) string { | ||||
| 	user := m.GetUser(userId) | ||||
| 	if user != nil { | ||||
| 		return user.Nickname | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *MMClient) GetStatus(userId string) string { | ||||
| 	res, resp := m.Client.GetUserStatus(userId, "") | ||||
| 	if resp.Error != nil { | ||||
| @@ -763,6 +795,14 @@ func (m *MMClient) GetStatus(userId string) string { | ||||
| 	return "offline" | ||||
| } | ||||
|  | ||||
| func (m *MMClient) UpdateStatus(userId string, status string) error { | ||||
| 	_, resp := m.Client.UpdateUserStatus(userId, &model.Status{Status: status}) | ||||
| 	if resp.Error != nil { | ||||
| 		return resp.Error | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *MMClient) GetStatuses() map[string]string { | ||||
| 	var ids []string | ||||
| 	statuses := make(map[string]string) | ||||
| @@ -900,7 +940,8 @@ func supportedVersion(version string) bool { | ||||
| 	if strings.HasPrefix(version, "3.8.0") || | ||||
| 		strings.HasPrefix(version, "3.9.0") || | ||||
| 		strings.HasPrefix(version, "3.10.0") || | ||||
| 		strings.HasPrefix(version, "4.") { | ||||
| 		strings.HasPrefix(version, "4.") || | ||||
| 		strings.HasPrefix(version, "5.") { | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
|   | ||||
| @@ -6,13 +6,15 @@ import ( | ||||
| 	"crypto/tls" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"github.com/gorilla/schema" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/gorilla/schema" | ||||
| 	"github.com/nlopes/slack" | ||||
| ) | ||||
|  | ||||
| // OMessage for mattermost incoming webhook. (send to mattermost) | ||||
| @@ -22,7 +24,7 @@ type OMessage struct { | ||||
| 	IconEmoji   string                 `json:"icon_emoji,omitempty"` | ||||
| 	UserName    string                 `json:"username,omitempty"` | ||||
| 	Text        string                 `json:"text"` | ||||
| 	Attachments interface{}            `json:"attachments,omitempty"` | ||||
| 	Attachments []slack.Attachment     `json:"attachments,omitempty"` | ||||
| 	Type        string                 `json:"type,omitempty"` | ||||
| 	Props       map[string]interface{} `json:"props"` | ||||
| } | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/github.com/42wim/go-gitter/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/42wim/go-gitter/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| .idea | ||||
| /test | ||||
| app.yaml | ||||
							
								
								
									
										154
									
								
								vendor/github.com/42wim/go-gitter/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								vendor/github.com/42wim/go-gitter/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
| # gitter | ||||
| Gitter API in Go | ||||
| https://developer.gitter.im | ||||
|  | ||||
| #### Install | ||||
|  | ||||
| `go get github.com/sromku/go-gitter` | ||||
|  | ||||
| - [Initialize](#initialize) | ||||
| - [Users](#users) | ||||
| - [Rooms](#rooms) | ||||
| - [Messages](#messages) | ||||
| - [Stream](#stream) | ||||
| - [Faye (Experimental)](#faye-experimental) | ||||
| - [Debug](#debug) | ||||
| - [App Engine](#app-engine) | ||||
|  | ||||
| ##### Initialize | ||||
| ``` Go | ||||
| api := gitter.New("YOUR_ACCESS_TOKEN") | ||||
| ``` | ||||
|  | ||||
| ##### Users | ||||
|  | ||||
| - Get current user | ||||
|  | ||||
| 	``` Go | ||||
| 	user, err := api.GetUser() | ||||
| 	``` | ||||
|  | ||||
| ##### Rooms | ||||
|  | ||||
| - Get all rooms | ||||
| 	``` Go | ||||
| 	rooms, err := api.GetRooms() | ||||
| 	``` | ||||
|  | ||||
| - Get room by id | ||||
| 	``` Go | ||||
| 	room, err := api.GetRoom("roomID") | ||||
| 	``` | ||||
|  | ||||
| - Get rooms of some user | ||||
| 	``` Go | ||||
| 	rooms, err := api.GetRooms("userID") | ||||
| 	``` | ||||
|  | ||||
| - Join room | ||||
| 	``` Go | ||||
| 	room, err := api.JoinRoom("roomID", "userID") | ||||
| 	``` | ||||
| 	 | ||||
| - Leave room | ||||
| 	``` Go | ||||
| 	room, err := api.LeaveRoom("roomID", "userID") | ||||
| 	``` | ||||
|  | ||||
| - Get room id | ||||
| 	``` Go | ||||
| 	id, err := api.GetRoomId("room/uri") | ||||
| 	``` | ||||
|  | ||||
| - Search gitter rooms | ||||
| 	``` Go | ||||
| 	rooms, err := api.SearchRooms("search/string") | ||||
| 	``` | ||||
| ##### Messages | ||||
|  | ||||
| - Get messages of room | ||||
| 	``` Go | ||||
| 	messages, err := api.GetMessages("roomID", nil) | ||||
| 	``` | ||||
|  | ||||
| - Get one message | ||||
| 	``` Go | ||||
| 	message, err := api.GetMessage("roomID", "messageID") | ||||
| 	``` | ||||
|  | ||||
| - Send message | ||||
| 	``` Go | ||||
| 	err := api.SendMessage("roomID", "free chat text") | ||||
| 	``` | ||||
|  | ||||
| ##### Stream | ||||
|  | ||||
| Create stream to the room and start listening to incoming messages | ||||
|  | ||||
| ``` Go | ||||
| stream := api.Stream(room.Id) | ||||
| go api.Listen(stream) | ||||
|  | ||||
| for { | ||||
|     event := <-stream.Event | ||||
|     switch ev := event.Data.(type) { | ||||
|     case *gitter.MessageReceived: | ||||
|         fmt.Println(ev.Message.From.Username + ": " + ev.Message.Text) | ||||
|     case *gitter.GitterConnectionClosed: | ||||
|         // connection was closed | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Close stream connection | ||||
|  | ||||
| ``` Go | ||||
| stream.Close() | ||||
| ``` | ||||
|  | ||||
| ##### Faye (Experimental) | ||||
|  | ||||
| ``` Go | ||||
| faye := api.Faye(room.ID) | ||||
| go faye.Listen() | ||||
|  | ||||
| for { | ||||
|     event := <-faye.Event | ||||
|     switch ev := event.Data.(type) { | ||||
|     case *gitter.MessageReceived: | ||||
|         fmt.Println(ev.Message.From.Username + ": " + ev.Message.Text) | ||||
|     case *gitter.GitterConnectionClosed: //this one is never called in Faye | ||||
|         // connection was closed | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ##### Debug | ||||
|  | ||||
| You can print the internal errors by enabling debug to true | ||||
|  | ||||
| ``` Go | ||||
| api.SetDebug(true, nil) | ||||
| ``` | ||||
|  | ||||
| You can also define your own `io.Writer` in case you want to persist the logs somewhere. | ||||
| For example keeping the errors on file | ||||
|  | ||||
| ``` Go | ||||
| logFile, err := os.Create("gitter.log") | ||||
| api.SetDebug(true, logFile) | ||||
| ``` | ||||
|  | ||||
| ##### App Engine | ||||
|  | ||||
| Initialize app engine client and continue as usual | ||||
|  | ||||
| ``` Go | ||||
| c := appengine.NewContext(r) | ||||
| client := urlfetch.Client(c) | ||||
|  | ||||
| api := gitter.New("YOUR_ACCESS_TOKEN") | ||||
| api.SetClient(client) | ||||
| ``` | ||||
|  | ||||
| [Documentation](https://godoc.org/github.com/sromku/go-gitter) | ||||
							
								
								
									
										27
									
								
								vendor/github.com/42wim/go-ircevent/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/42wim/go-ircevent/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,27 +0,0 @@ | ||||
| // Copyright (c) 2009 Thomas Jager. All rights reserved. | ||||
| // | ||||
| // Redistribution and use in source and binary forms, with or without | ||||
| // modification, are permitted provided that the following conditions are | ||||
| // met: | ||||
| // | ||||
| //    * Redistributions of source code must retain the above copyright | ||||
| // notice, this list of conditions and the following disclaimer. | ||||
| //    * Redistributions in binary form must reproduce the above | ||||
| // copyright notice, this list of conditions and the following disclaimer | ||||
| // in the documentation and/or other materials provided with the | ||||
| // distribution. | ||||
| //    * Neither the name of Google Inc. nor the names of its | ||||
| // contributors may be used to endorse or promote products derived from | ||||
| // this software without specific prior written permission. | ||||
| // | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										578
									
								
								vendor/github.com/42wim/go-ircevent/irc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										578
									
								
								vendor/github.com/42wim/go-ircevent/irc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,578 +0,0 @@ | ||||
| // Copyright 2009 Thomas Jager <mail@jager.no>  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| /* | ||||
| This package provides an event based IRC client library. It allows to | ||||
| register callbacks for the events you need to handle. Its features | ||||
| include handling standard CTCP, reconnecting on errors and detecting | ||||
| stones servers. | ||||
| Details of the IRC protocol can be found in the following RFCs: | ||||
| https://tools.ietf.org/html/rfc1459 | ||||
| https://tools.ietf.org/html/rfc2810 | ||||
| https://tools.ietf.org/html/rfc2811 | ||||
| https://tools.ietf.org/html/rfc2812 | ||||
| https://tools.ietf.org/html/rfc2813 | ||||
| The details of the client-to-client protocol (CTCP) can be found here: http://www.irchelp.org/irchelp/rfc/ctcpspec.html | ||||
| */ | ||||
|  | ||||
| package irc | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"crypto/tls" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	VERSION = "go-ircevent v2.1" | ||||
| ) | ||||
|  | ||||
| var ErrDisconnected = errors.New("Disconnect Called") | ||||
|  | ||||
| // Read data from a connection. To be used as a goroutine. | ||||
| func (irc *Connection) readLoop() { | ||||
| 	defer irc.Done() | ||||
| 	br := bufio.NewReaderSize(irc.socket, 512) | ||||
|  | ||||
| 	errChan := irc.ErrorChan() | ||||
|  | ||||
| 	for { | ||||
| 		select { | ||||
| 		case <-irc.end: | ||||
| 			return | ||||
| 		default: | ||||
| 			// Set a read deadline based on the combined timeout and ping frequency | ||||
| 			// We should ALWAYS have received a response from the server within the timeout | ||||
| 			// after our own pings | ||||
| 			if irc.socket != nil { | ||||
| 				irc.socket.SetReadDeadline(time.Now().Add(irc.Timeout + irc.PingFreq)) | ||||
| 			} | ||||
|  | ||||
| 			msg, err := br.ReadString('\n') | ||||
|  | ||||
| 			// We got past our blocking read, so bin timeout | ||||
| 			if irc.socket != nil { | ||||
| 				var zero time.Time | ||||
| 				irc.socket.SetReadDeadline(zero) | ||||
| 			} | ||||
|  | ||||
| 			if err != nil { | ||||
| 				errChan <- err | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			if irc.Debug { | ||||
| 				irc.Log.Printf("<-- %s\n", strings.TrimSpace(msg)) | ||||
| 			} | ||||
|  | ||||
| 			irc.Lock() | ||||
| 			irc.lastMessage = time.Now() | ||||
| 			irc.Unlock() | ||||
| 			event, err := parseToEvent(msg) | ||||
| 			event.Connection = irc | ||||
| 			if err == nil { | ||||
| 				/* XXX: len(args) == 0: args should be empty */ | ||||
| 				irc.RunCallbacks(event) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Unescape tag values as defined in the IRCv3.2 message tags spec | ||||
| // http://ircv3.net/specs/core/message-tags-3.2.html | ||||
| func unescapeTagValue(value string) string { | ||||
| 	value = strings.Replace(value, "\\:", ";", -1) | ||||
| 	value = strings.Replace(value, "\\s", " ", -1) | ||||
| 	value = strings.Replace(value, "\\\\", "\\", -1) | ||||
| 	value = strings.Replace(value, "\\r", "\r", -1) | ||||
| 	value = strings.Replace(value, "\\n", "\n", -1) | ||||
| 	return value | ||||
| } | ||||
|  | ||||
| //Parse raw irc messages | ||||
| func parseToEvent(msg string) (*Event, error) { | ||||
| 	msg = strings.TrimSuffix(msg, "\n") //Remove \r\n | ||||
| 	msg = strings.TrimSuffix(msg, "\r") | ||||
| 	event := &Event{Raw: msg} | ||||
| 	if len(msg) < 5 { | ||||
| 		return nil, errors.New("Malformed msg from server") | ||||
| 	} | ||||
|  | ||||
| 	if msg[0] == '@' { | ||||
| 		// IRCv3 Message Tags | ||||
| 		if i := strings.Index(msg, " "); i > -1 { | ||||
| 			event.Tags = make(map[string]string) | ||||
| 			tags := strings.Split(msg[1:i], ";") | ||||
| 			for _, data := range tags { | ||||
| 				parts := strings.SplitN(data, "=", 2) | ||||
| 				if len(parts) == 1 { | ||||
| 					event.Tags[parts[0]] = "" | ||||
| 				} else { | ||||
| 					event.Tags[parts[0]] = unescapeTagValue(parts[1]) | ||||
| 				} | ||||
| 			} | ||||
| 			msg = msg[i+1 : len(msg)] | ||||
| 		} else { | ||||
| 			return nil, errors.New("Malformed msg from server") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if msg[0] == ':' { | ||||
| 		if i := strings.Index(msg, " "); i > -1 { | ||||
| 			event.Source = msg[1:i] | ||||
| 			msg = msg[i+1 : len(msg)] | ||||
|  | ||||
| 		} else { | ||||
| 			return nil, errors.New("Malformed msg from server") | ||||
| 		} | ||||
|  | ||||
| 		if i, j := strings.Index(event.Source, "!"), strings.Index(event.Source, "@"); i > -1 && j > -1 && i < j { | ||||
| 			event.Nick = event.Source[0:i] | ||||
| 			event.User = event.Source[i+1 : j] | ||||
| 			event.Host = event.Source[j+1 : len(event.Source)] | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	split := strings.SplitN(msg, " :", 2) | ||||
| 	args := strings.Split(split[0], " ") | ||||
| 	event.Code = strings.ToUpper(args[0]) | ||||
| 	event.Arguments = args[1:] | ||||
| 	if len(split) > 1 { | ||||
| 		event.Arguments = append(event.Arguments, split[1]) | ||||
| 	} | ||||
| 	return event, nil | ||||
|  | ||||
| } | ||||
|  | ||||
| // Loop to write to a connection. To be used as a goroutine. | ||||
| func (irc *Connection) writeLoop() { | ||||
| 	defer irc.Done() | ||||
| 	errChan := irc.ErrorChan() | ||||
| 	for { | ||||
| 		select { | ||||
| 		case <-irc.end: | ||||
| 			return | ||||
| 		case b, ok := <-irc.pwrite: | ||||
| 			if !ok || b == "" || irc.socket == nil { | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			if irc.Debug { | ||||
| 				irc.Log.Printf("--> %s\n", strings.TrimSpace(b)) | ||||
| 			} | ||||
|  | ||||
| 			// Set a write deadline based on the time out | ||||
| 			irc.socket.SetWriteDeadline(time.Now().Add(irc.Timeout)) | ||||
|  | ||||
| 			_, err := irc.socket.Write([]byte(b)) | ||||
|  | ||||
| 			// Past blocking write, bin timeout | ||||
| 			var zero time.Time | ||||
| 			irc.socket.SetWriteDeadline(zero) | ||||
|  | ||||
| 			if err != nil { | ||||
| 				errChan <- err | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Pings the server if we have not received any messages for 5 minutes | ||||
| // to keep the connection alive. To be used as a goroutine. | ||||
| func (irc *Connection) pingLoop() { | ||||
| 	defer irc.Done() | ||||
| 	ticker := time.NewTicker(1 * time.Minute) // Tick every minute for monitoring | ||||
| 	ticker2 := time.NewTicker(irc.PingFreq)   // Tick at the ping frequency. | ||||
| 	for { | ||||
| 		select { | ||||
| 		case <-ticker.C: | ||||
| 			//Ping if we haven't received anything from the server within the keep alive period | ||||
| 			if time.Since(irc.lastMessage) >= irc.KeepAlive { | ||||
| 				irc.SendRawf("PING %d", time.Now().UnixNano()) | ||||
| 			} | ||||
| 		case <-ticker2.C: | ||||
| 			//Ping at the ping frequency | ||||
| 			irc.SendRawf("PING %d", time.Now().UnixNano()) | ||||
| 			//Try to recapture nickname if it's not as configured. | ||||
| 			irc.Lock() | ||||
| 			if irc.nick != irc.nickcurrent { | ||||
| 				irc.nickcurrent = irc.nick | ||||
| 				irc.SendRawf("NICK %s", irc.nick) | ||||
| 			} | ||||
| 			irc.Unlock() | ||||
| 		case <-irc.end: | ||||
| 			ticker.Stop() | ||||
| 			ticker2.Stop() | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (irc *Connection) isQuitting() bool { | ||||
| 	irc.Lock() | ||||
| 	defer irc.Unlock() | ||||
| 	return irc.quit | ||||
| } | ||||
|  | ||||
| // Main loop to control the connection. | ||||
| func (irc *Connection) Loop() { | ||||
| 	errChan := irc.ErrorChan() | ||||
| 	connTime := time.Now() | ||||
| 	for !irc.isQuitting() { | ||||
| 		err := <-errChan | ||||
| 		close(irc.end) | ||||
| 		irc.Wait() | ||||
| 		for !irc.isQuitting() { | ||||
| 			irc.Log.Printf("Error, disconnected: %s\n", err) | ||||
| 			if time.Now().Sub(connTime) < time.Second*5 { | ||||
| 				irc.Log.Println("Rreconnecting too fast, sleeping 60 seconds") | ||||
| 				time.Sleep(60 * time.Second) | ||||
| 			} | ||||
| 			if err = irc.Reconnect(); err != nil { | ||||
| 				irc.Log.Printf("Error while reconnecting: %s\n", err) | ||||
| 				time.Sleep(60 * time.Second) | ||||
| 			} else { | ||||
| 				errChan = irc.ErrorChan() | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		connTime = time.Now() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Quit the current connection and disconnect from the server | ||||
| // RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.1.6 | ||||
| func (irc *Connection) Quit() { | ||||
| 	quit := "QUIT" | ||||
|  | ||||
| 	if irc.QuitMessage != "" { | ||||
| 		quit = fmt.Sprintf("QUIT :%s", irc.QuitMessage) | ||||
| 	} | ||||
|  | ||||
| 	irc.SendRaw(quit) | ||||
| 	irc.Lock() | ||||
| 	irc.stopped = true | ||||
| 	irc.quit = true | ||||
| 	irc.Unlock() | ||||
| } | ||||
|  | ||||
| // Use the connection to join a given channel. | ||||
| // RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.2.1 | ||||
| func (irc *Connection) Join(channel string) { | ||||
| 	irc.pwrite <- fmt.Sprintf("JOIN %s\r\n", channel) | ||||
| } | ||||
|  | ||||
| // Leave a given channel. | ||||
| // RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.2.2 | ||||
| func (irc *Connection) Part(channel string) { | ||||
| 	irc.pwrite <- fmt.Sprintf("PART %s\r\n", channel) | ||||
| } | ||||
|  | ||||
| // Send a notification to a nickname. This is similar to Privmsg but must not receive replies. | ||||
| // RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.4.2 | ||||
| func (irc *Connection) Notice(target, message string) { | ||||
| 	irc.pwrite <- fmt.Sprintf("NOTICE %s :%s\r\n", target, message) | ||||
| } | ||||
|  | ||||
| // Send a formated notification to a nickname. | ||||
| // RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.4.2 | ||||
| func (irc *Connection) Noticef(target, format string, a ...interface{}) { | ||||
| 	irc.Notice(target, fmt.Sprintf(format, a...)) | ||||
| } | ||||
|  | ||||
| // Send (action) message to a target (channel or nickname). | ||||
| // No clear RFC on this one... | ||||
| func (irc *Connection) Action(target, message string) { | ||||
| 	irc.pwrite <- fmt.Sprintf("PRIVMSG %s :\001ACTION %s\001\r\n", target, message) | ||||
| } | ||||
|  | ||||
| // Send formatted (action) message to a target (channel or nickname). | ||||
| func (irc *Connection) Actionf(target, format string, a ...interface{}) { | ||||
| 	irc.Action(target, fmt.Sprintf(format, a...)) | ||||
| } | ||||
|  | ||||
| // Send (private) message to a target (channel or nickname). | ||||
| // RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.4.1 | ||||
| func (irc *Connection) Privmsg(target, message string) { | ||||
| 	irc.pwrite <- fmt.Sprintf("PRIVMSG %s :%s\r\n", target, message) | ||||
| } | ||||
|  | ||||
| // Send formated string to specified target (channel or nickname). | ||||
| func (irc *Connection) Privmsgf(target, format string, a ...interface{}) { | ||||
| 	irc.Privmsg(target, fmt.Sprintf(format, a...)) | ||||
| } | ||||
|  | ||||
| // Kick <user> from <channel> with <msg>. For no message, pass empty string ("") | ||||
| func (irc *Connection) Kick(user, channel, msg string) { | ||||
| 	var cmd bytes.Buffer | ||||
| 	cmd.WriteString(fmt.Sprintf("KICK %s %s", channel, user)) | ||||
| 	if msg != "" { | ||||
| 		cmd.WriteString(fmt.Sprintf(" :%s", msg)) | ||||
| 	} | ||||
| 	cmd.WriteString("\r\n") | ||||
| 	irc.pwrite <- cmd.String() | ||||
| } | ||||
|  | ||||
| // Kick all <users> from <channel> with <msg>. For no message, pass | ||||
| // empty string ("") | ||||
| func (irc *Connection) MultiKick(users []string, channel string, msg string) { | ||||
| 	var cmd bytes.Buffer | ||||
| 	cmd.WriteString(fmt.Sprintf("KICK %s %s", channel, strings.Join(users, ","))) | ||||
| 	if msg != "" { | ||||
| 		cmd.WriteString(fmt.Sprintf(" :%s", msg)) | ||||
| 	} | ||||
| 	cmd.WriteString("\r\n") | ||||
| 	irc.pwrite <- cmd.String() | ||||
| } | ||||
|  | ||||
| // Send raw string. | ||||
| func (irc *Connection) SendRaw(message string) { | ||||
| 	irc.pwrite <- message + "\r\n" | ||||
| } | ||||
|  | ||||
| // Send raw formated string. | ||||
| func (irc *Connection) SendRawf(format string, a ...interface{}) { | ||||
| 	irc.SendRaw(fmt.Sprintf(format, a...)) | ||||
| } | ||||
|  | ||||
| // Set (new) nickname. | ||||
| // RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.1.2 | ||||
| func (irc *Connection) Nick(n string) { | ||||
| 	irc.nick = n | ||||
| 	irc.SendRawf("NICK %s", n) | ||||
| } | ||||
|  | ||||
| // Determine nick currently used with the connection. | ||||
| func (irc *Connection) GetNick() string { | ||||
| 	return irc.nickcurrent | ||||
| } | ||||
|  | ||||
| // Query information about a particular nickname. | ||||
| // RFC 1459: https://tools.ietf.org/html/rfc1459#section-4.5.2 | ||||
| func (irc *Connection) Whois(nick string) { | ||||
| 	irc.SendRawf("WHOIS %s", nick) | ||||
| } | ||||
|  | ||||
| // Query information about a given nickname in the server. | ||||
| // RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.5.1 | ||||
| func (irc *Connection) Who(nick string) { | ||||
| 	irc.SendRawf("WHO %s", nick) | ||||
| } | ||||
|  | ||||
| // Set different modes for a target (channel or nickname). | ||||
| // RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.2.3 | ||||
| func (irc *Connection) Mode(target string, modestring ...string) { | ||||
| 	if len(modestring) > 0 { | ||||
| 		mode := strings.Join(modestring, " ") | ||||
| 		irc.SendRawf("MODE %s %s", target, mode) | ||||
| 		return | ||||
| 	} | ||||
| 	irc.SendRawf("MODE %s", target) | ||||
| } | ||||
|  | ||||
| func (irc *Connection) ErrorChan() chan error { | ||||
| 	return irc.Error | ||||
| } | ||||
|  | ||||
| // Returns true if the connection is connected to an IRC server. | ||||
| func (irc *Connection) Connected() bool { | ||||
| 	return !irc.stopped | ||||
| } | ||||
|  | ||||
| // A disconnect sends all buffered messages (if possible), | ||||
| // stops all goroutines and then closes the socket. | ||||
| func (irc *Connection) Disconnect() { | ||||
| 	if irc.socket != nil { | ||||
| 		irc.socket.Close() | ||||
| 	} | ||||
| 	irc.ErrorChan() <- ErrDisconnected | ||||
| } | ||||
|  | ||||
| // Reconnect to a server using the current connection. | ||||
| func (irc *Connection) Reconnect() error { | ||||
| 	irc.end = make(chan struct{}) | ||||
| 	return irc.Connect(irc.Server) | ||||
| } | ||||
|  | ||||
| // Connect to a given server using the current connection configuration. | ||||
| // This function also takes care of identification if a password is provided. | ||||
| // RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.1 | ||||
| func (irc *Connection) Connect(server string) error { | ||||
| 	irc.Server = server | ||||
| 	// mark Server as stopped since there can be an error during connect | ||||
| 	irc.stopped = true | ||||
|  | ||||
| 	// make sure everything is ready for connection | ||||
| 	if len(irc.Server) == 0 { | ||||
| 		return errors.New("empty 'server'") | ||||
| 	} | ||||
| 	if strings.Count(irc.Server, ":") != 1 { | ||||
| 		return errors.New("wrong number of ':' in address") | ||||
| 	} | ||||
| 	if strings.Index(irc.Server, ":") == 0 { | ||||
| 		return errors.New("hostname is missing") | ||||
| 	} | ||||
| 	if strings.Index(irc.Server, ":") == len(irc.Server)-1 { | ||||
| 		return errors.New("port missing") | ||||
| 	} | ||||
| 	// check for valid range | ||||
| 	ports := strings.Split(irc.Server, ":")[1] | ||||
| 	port, err := strconv.Atoi(ports) | ||||
| 	if err != nil { | ||||
| 		return errors.New("extracting port failed") | ||||
| 	} | ||||
| 	if !((port >= 0) && (port <= 65535)) { | ||||
| 		return errors.New("port number outside valid range") | ||||
| 	} | ||||
| 	if irc.Log == nil { | ||||
| 		return errors.New("'Log' points to nil") | ||||
| 	} | ||||
| 	if len(irc.nick) == 0 { | ||||
| 		return errors.New("empty 'nick'") | ||||
| 	} | ||||
| 	if len(irc.user) == 0 { | ||||
| 		return errors.New("empty 'user'") | ||||
| 	} | ||||
|  | ||||
| 	if irc.UseTLS { | ||||
| 		dialer := &net.Dialer{Timeout: irc.Timeout} | ||||
| 		irc.socket, err = tls.DialWithDialer(dialer, "tcp", irc.Server, irc.TLSConfig) | ||||
| 	} else { | ||||
| 		irc.socket, err = net.DialTimeout("tcp", irc.Server, irc.Timeout) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	irc.stopped = false | ||||
| 	irc.Log.Printf("Connected to %s (%s)\n", irc.Server, irc.socket.RemoteAddr()) | ||||
|  | ||||
| 	irc.pwrite = make(chan string, 10) | ||||
| 	irc.Error = make(chan error, 2) | ||||
| 	irc.Add(3) | ||||
| 	go irc.readLoop() | ||||
| 	go irc.writeLoop() | ||||
| 	go irc.pingLoop() | ||||
| 	if len(irc.Password) > 0 { | ||||
| 		irc.pwrite <- fmt.Sprintf("PASS %s\r\n", irc.Password) | ||||
| 	} | ||||
|  | ||||
| 	err = irc.negotiateCaps() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	irc.pwrite <- fmt.Sprintf("NICK %s\r\n", irc.nick) | ||||
| 	irc.pwrite <- fmt.Sprintf("USER %s 0.0.0.0 0.0.0.0 :%s\r\n", irc.user, irc.user) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Negotiate IRCv3 capabilities | ||||
| func (irc *Connection) negotiateCaps() error { | ||||
| 	saslResChan := make(chan *SASLResult) | ||||
| 	if irc.UseSASL { | ||||
| 		irc.RequestCaps = append(irc.RequestCaps, "sasl") | ||||
| 		irc.setupSASLCallbacks(saslResChan) | ||||
| 	} | ||||
|  | ||||
| 	if len(irc.RequestCaps) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	cap_chan := make(chan bool, len(irc.RequestCaps)) | ||||
| 	irc.AddCallback("CAP", func(e *Event) { | ||||
| 		if len(e.Arguments) != 3 { | ||||
| 			return | ||||
| 		} | ||||
| 		command := e.Arguments[1] | ||||
|  | ||||
| 		if command == "LS" { | ||||
| 			missing_caps := len(irc.RequestCaps) | ||||
| 			for _, cap_name := range strings.Split(e.Arguments[2], " ") { | ||||
| 				for _, req_cap := range irc.RequestCaps { | ||||
| 					if cap_name == req_cap { | ||||
| 						irc.pwrite <- fmt.Sprintf("CAP REQ :%s\r\n", cap_name) | ||||
| 						missing_caps-- | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			for i := 0; i < missing_caps; i++ { | ||||
| 				cap_chan <- true | ||||
| 			} | ||||
| 		} else if command == "ACK" || command == "NAK" { | ||||
| 			for _, cap_name := range strings.Split(strings.TrimSpace(e.Arguments[2]), " ") { | ||||
| 				if cap_name == "" { | ||||
| 					continue | ||||
| 				} | ||||
|  | ||||
| 				if command == "ACK" { | ||||
| 					irc.AcknowledgedCaps = append(irc.AcknowledgedCaps, cap_name) | ||||
| 				} | ||||
| 				cap_chan <- true | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	irc.pwrite <- "CAP LS\r\n" | ||||
|  | ||||
| 	if irc.UseSASL { | ||||
| 		select { | ||||
| 		case res := <-saslResChan: | ||||
| 			if res.Failed { | ||||
| 				close(saslResChan) | ||||
| 				return res.Err | ||||
| 			} | ||||
| 		case <-time.After(time.Second * 15): | ||||
| 			close(saslResChan) | ||||
| 			return errors.New("SASL setup timed out. This shouldn't happen.") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Wait for all capabilities to be ACKed or NAKed before ending negotiation | ||||
| 	for i := 0; i < len(irc.RequestCaps); i++ { | ||||
| 		<-cap_chan | ||||
| 	} | ||||
| 	irc.pwrite <- fmt.Sprintf("CAP END\r\n") | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Create a connection with the (publicly visible) nickname and username. | ||||
| // The nickname is later used to address the user. Returns nil if nick | ||||
| // or user are empty. | ||||
| func IRC(nick, user string) *Connection { | ||||
| 	// catch invalid values | ||||
| 	if len(nick) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if len(user) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	irc := &Connection{ | ||||
| 		nick:        nick, | ||||
| 		nickcurrent: nick, | ||||
| 		user:        user, | ||||
| 		Log:         log.New(os.Stdout, "", log.LstdFlags), | ||||
| 		end:         make(chan struct{}), | ||||
| 		Version:     VERSION, | ||||
| 		KeepAlive:   4 * time.Minute, | ||||
| 		Timeout:     1 * time.Minute, | ||||
| 		PingFreq:    15 * time.Minute, | ||||
| 		SASLMech:    "PLAIN", | ||||
| 		QuitMessage: "", | ||||
| 	} | ||||
| 	irc.setupCallbacks() | ||||
| 	return irc | ||||
| } | ||||
							
								
								
									
										222
									
								
								vendor/github.com/42wim/go-ircevent/irc_callback.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										222
									
								
								vendor/github.com/42wim/go-ircevent/irc_callback.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,222 +0,0 @@ | ||||
| package irc | ||||
|  | ||||
| import ( | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // Register a callback to a connection and event code. A callback is a function | ||||
| // which takes only an Event pointer as parameter. Valid event codes are all | ||||
| // IRC/CTCP commands and error/response codes. This function returns the ID of | ||||
| // the registered callback for later management. | ||||
| func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) int { | ||||
| 	eventcode = strings.ToUpper(eventcode) | ||||
| 	id := 0 | ||||
| 	if _, ok := irc.events[eventcode]; !ok { | ||||
| 		irc.events[eventcode] = make(map[int]func(*Event)) | ||||
| 		id = 0 | ||||
| 	} else { | ||||
| 		id = len(irc.events[eventcode]) | ||||
| 	} | ||||
| 	irc.events[eventcode][id] = callback | ||||
| 	return id | ||||
| } | ||||
|  | ||||
| // Remove callback i (ID) from the given event code. This functions returns | ||||
| // true upon success, false if any error occurs. | ||||
| func (irc *Connection) RemoveCallback(eventcode string, i int) bool { | ||||
| 	eventcode = strings.ToUpper(eventcode) | ||||
|  | ||||
| 	if event, ok := irc.events[eventcode]; ok { | ||||
| 		if _, ok := event[i]; ok { | ||||
| 			delete(irc.events[eventcode], i) | ||||
| 			return true | ||||
| 		} | ||||
| 		irc.Log.Printf("Event found, but no callback found at id %d\n", i) | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	irc.Log.Println("Event not found") | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Remove all callbacks from a given event code. It returns true | ||||
| // if given event code is found and cleared. | ||||
| func (irc *Connection) ClearCallback(eventcode string) bool { | ||||
| 	eventcode = strings.ToUpper(eventcode) | ||||
|  | ||||
| 	if _, ok := irc.events[eventcode]; ok { | ||||
| 		irc.events[eventcode] = make(map[int]func(*Event)) | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	irc.Log.Println("Event not found") | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Replace callback i (ID) associated with a given event code with a new callback function. | ||||
| func (irc *Connection) ReplaceCallback(eventcode string, i int, callback func(*Event)) { | ||||
| 	eventcode = strings.ToUpper(eventcode) | ||||
|  | ||||
| 	if event, ok := irc.events[eventcode]; ok { | ||||
| 		if _, ok := event[i]; ok { | ||||
| 			event[i] = callback | ||||
| 			return | ||||
| 		} | ||||
| 		irc.Log.Printf("Event found, but no callback found at id %d\n", i) | ||||
| 	} | ||||
| 	irc.Log.Printf("Event not found. Use AddCallBack\n") | ||||
| } | ||||
|  | ||||
| // Execute all callbacks associated with a given event. | ||||
| func (irc *Connection) RunCallbacks(event *Event) { | ||||
| 	msg := event.Message() | ||||
| 	if event.Code == "PRIVMSG" && len(msg) > 2 && msg[0] == '\x01' { | ||||
| 		event.Code = "CTCP" //Unknown CTCP | ||||
|  | ||||
| 		if i := strings.LastIndex(msg, "\x01"); i > 0 { | ||||
| 			msg = msg[1:i] | ||||
| 		} else { | ||||
| 			irc.Log.Printf("Invalid CTCP Message: %s\n", strconv.Quote(msg)) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		if msg == "VERSION" { | ||||
| 			event.Code = "CTCP_VERSION" | ||||
|  | ||||
| 		} else if msg == "TIME" { | ||||
| 			event.Code = "CTCP_TIME" | ||||
|  | ||||
| 		} else if strings.HasPrefix(msg, "PING") { | ||||
| 			event.Code = "CTCP_PING" | ||||
|  | ||||
| 		} else if msg == "USERINFO" { | ||||
| 			event.Code = "CTCP_USERINFO" | ||||
|  | ||||
| 		} else if msg == "CLIENTINFO" { | ||||
| 			event.Code = "CTCP_CLIENTINFO" | ||||
|  | ||||
| 		} else if strings.HasPrefix(msg, "ACTION") { | ||||
| 			event.Code = "CTCP_ACTION" | ||||
| 			if len(msg) > 6 { | ||||
| 				msg = msg[7:] | ||||
| 			} else { | ||||
| 				msg = "" | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		event.Arguments[len(event.Arguments)-1] = msg | ||||
| 	} | ||||
|  | ||||
| 	if callbacks, ok := irc.events[event.Code]; ok { | ||||
| 		if irc.VerboseCallbackHandler { | ||||
| 			irc.Log.Printf("%v (%v) >> %#v\n", event.Code, len(callbacks), event) | ||||
| 		} | ||||
|  | ||||
| 		for _, callback := range callbacks { | ||||
| 			callback(event) | ||||
| 		} | ||||
| 	} else if irc.VerboseCallbackHandler { | ||||
| 		irc.Log.Printf("%v (0) >> %#v\n", event.Code, event) | ||||
| 	} | ||||
|  | ||||
| 	if callbacks, ok := irc.events["*"]; ok { | ||||
| 		if irc.VerboseCallbackHandler { | ||||
| 			irc.Log.Printf("%v (0) >> %#v\n", event.Code, event) | ||||
| 		} | ||||
|  | ||||
| 		for _, callback := range callbacks { | ||||
| 			callback(event) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Set up some initial callbacks to handle the IRC/CTCP protocol. | ||||
| func (irc *Connection) setupCallbacks() { | ||||
| 	irc.events = make(map[string]map[int]func(*Event)) | ||||
|  | ||||
| 	//Handle error events. | ||||
| 	irc.AddCallback("ERROR", func(e *Event) { irc.Disconnect() }) | ||||
|  | ||||
| 	//Handle ping events | ||||
| 	irc.AddCallback("PING", func(e *Event) { irc.SendRaw("PONG :" + e.Message()) }) | ||||
|  | ||||
| 	//Version handler | ||||
| 	irc.AddCallback("CTCP_VERSION", func(e *Event) { | ||||
| 		irc.SendRawf("NOTICE %s :\x01VERSION %s\x01", e.Nick, irc.Version) | ||||
| 	}) | ||||
|  | ||||
| 	irc.AddCallback("CTCP_USERINFO", func(e *Event) { | ||||
| 		irc.SendRawf("NOTICE %s :\x01USERINFO %s\x01", e.Nick, irc.user) | ||||
| 	}) | ||||
|  | ||||
| 	irc.AddCallback("CTCP_CLIENTINFO", func(e *Event) { | ||||
| 		irc.SendRawf("NOTICE %s :\x01CLIENTINFO PING VERSION TIME USERINFO CLIENTINFO\x01", e.Nick) | ||||
| 	}) | ||||
|  | ||||
| 	irc.AddCallback("CTCP_TIME", func(e *Event) { | ||||
| 		ltime := time.Now() | ||||
| 		irc.SendRawf("NOTICE %s :\x01TIME %s\x01", e.Nick, ltime.String()) | ||||
| 	}) | ||||
|  | ||||
| 	irc.AddCallback("CTCP_PING", func(e *Event) { irc.SendRawf("NOTICE %s :\x01%s\x01", e.Nick, e.Message()) }) | ||||
|  | ||||
| 	// 437: ERR_UNAVAILRESOURCE "<nick/channel> :Nick/channel is temporarily unavailable" | ||||
| 	// Add a _ to current nick. If irc.nickcurrent is empty this cannot | ||||
| 	// work. It has to be set somewhere first in case the nick is already | ||||
| 	// taken or unavailable from the beginning. | ||||
| 	irc.AddCallback("437", func(e *Event) { | ||||
| 		// If irc.nickcurrent hasn't been set yet, set to irc.nick | ||||
| 		if irc.nickcurrent == "" { | ||||
| 			irc.nickcurrent = irc.nick | ||||
| 		} | ||||
|  | ||||
| 		if len(irc.nickcurrent) > 8 { | ||||
| 			irc.nickcurrent = "_" + irc.nickcurrent | ||||
| 		} else { | ||||
| 			irc.nickcurrent = irc.nickcurrent + "_" | ||||
| 		} | ||||
| 		irc.SendRawf("NICK %s", irc.nickcurrent) | ||||
| 	}) | ||||
|  | ||||
| 	// 433: ERR_NICKNAMEINUSE "<nick> :Nickname is already in use" | ||||
| 	// Add a _ to current nick. | ||||
| 	irc.AddCallback("433", func(e *Event) { | ||||
| 		// If irc.nickcurrent hasn't been set yet, set to irc.nick | ||||
| 		if irc.nickcurrent == "" { | ||||
| 			irc.nickcurrent = irc.nick | ||||
| 		} | ||||
|  | ||||
| 		if len(irc.nickcurrent) > 8 { | ||||
| 			irc.nickcurrent = "_" + irc.nickcurrent | ||||
| 		} else { | ||||
| 			irc.nickcurrent = irc.nickcurrent + "_" | ||||
| 		} | ||||
| 		irc.SendRawf("NICK %s", irc.nickcurrent) | ||||
| 	}) | ||||
|  | ||||
| 	irc.AddCallback("PONG", func(e *Event) { | ||||
| 		ns, _ := strconv.ParseInt(e.Message(), 10, 64) | ||||
| 		delta := time.Duration(time.Now().UnixNano() - ns) | ||||
| 		if irc.Debug { | ||||
| 			irc.Log.Printf("Lag: %.3f s\n", delta.Seconds()) | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	// NICK Define a nickname. | ||||
| 	// Set irc.nickcurrent to the new nick actually used in this connection. | ||||
| 	irc.AddCallback("NICK", func(e *Event) { | ||||
| 		if e.Nick == irc.nick { | ||||
| 			irc.nickcurrent = e.Message() | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	// 1: RPL_WELCOME "Welcome to the Internet Relay Network <nick>!<user>@<host>" | ||||
| 	// Set irc.nickcurrent to the actually used nick in this connection. | ||||
| 	irc.AddCallback("001", func(e *Event) { | ||||
| 		irc.Lock() | ||||
| 		irc.nickcurrent = e.Arguments[0] | ||||
| 		irc.Unlock() | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										53
									
								
								vendor/github.com/42wim/go-ircevent/irc_sasl.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										53
									
								
								vendor/github.com/42wim/go-ircevent/irc_sasl.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,53 +0,0 @@ | ||||
| package irc | ||||
|  | ||||
| import ( | ||||
| 	"encoding/base64" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| type SASLResult struct { | ||||
| 	Failed bool | ||||
| 	Err    error | ||||
| } | ||||
|  | ||||
| func (irc *Connection) setupSASLCallbacks(result chan<- *SASLResult) { | ||||
| 	irc.AddCallback("CAP", func(e *Event) { | ||||
| 		if len(e.Arguments) == 3 { | ||||
| 			if e.Arguments[1] == "LS" { | ||||
| 				if !strings.Contains(e.Arguments[2], "sasl") { | ||||
| 					result <- &SASLResult{true, errors.New("no SASL capability " + e.Arguments[2])} | ||||
| 				} | ||||
| 			} | ||||
| 			if e.Arguments[1] == "ACK" { | ||||
| 				if irc.SASLMech != "PLAIN" { | ||||
| 					result <- &SASLResult{true, errors.New("only PLAIN is supported")} | ||||
| 				} | ||||
| 				irc.SendRaw("AUTHENTICATE " + irc.SASLMech) | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
| 	irc.AddCallback("AUTHENTICATE", func(e *Event) { | ||||
| 		str := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s\x00%s\x00%s", irc.SASLLogin, irc.SASLLogin, irc.SASLPassword))) | ||||
| 		irc.SendRaw("AUTHENTICATE " + str) | ||||
| 	}) | ||||
| 	irc.AddCallback("901", func(e *Event) { | ||||
| 		irc.SendRaw("CAP END") | ||||
| 		irc.SendRaw("QUIT") | ||||
| 		result <- &SASLResult{true, errors.New(e.Arguments[1])} | ||||
| 	}) | ||||
| 	irc.AddCallback("902", func(e *Event) { | ||||
| 		irc.SendRaw("CAP END") | ||||
| 		irc.SendRaw("QUIT") | ||||
| 		result <- &SASLResult{true, errors.New(e.Arguments[1])} | ||||
| 	}) | ||||
| 	irc.AddCallback("903", func(e *Event) { | ||||
| 		result <- &SASLResult{false, nil} | ||||
| 	}) | ||||
| 	irc.AddCallback("904", func(e *Event) { | ||||
| 		irc.SendRaw("CAP END") | ||||
| 		irc.SendRaw("QUIT") | ||||
| 		result <- &SASLResult{true, errors.New(e.Arguments[1])} | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										76
									
								
								vendor/github.com/42wim/go-ircevent/irc_struct.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										76
									
								
								vendor/github.com/42wim/go-ircevent/irc_struct.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,76 +0,0 @@ | ||||
| // Copyright 2009 Thomas Jager <mail@jager.no>  All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package irc | ||||
|  | ||||
| import ( | ||||
| 	"crypto/tls" | ||||
| 	"log" | ||||
| 	"net" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| type Connection struct { | ||||
| 	sync.Mutex | ||||
| 	sync.WaitGroup | ||||
| 	Debug            bool | ||||
| 	Error            chan error | ||||
| 	Password         string | ||||
| 	UseTLS           bool | ||||
| 	UseSASL          bool | ||||
| 	RequestCaps      []string | ||||
| 	AcknowledgedCaps []string | ||||
| 	SASLLogin        string | ||||
| 	SASLPassword     string | ||||
| 	SASLMech         string | ||||
| 	TLSConfig        *tls.Config | ||||
| 	Version          string | ||||
| 	Timeout          time.Duration | ||||
| 	PingFreq         time.Duration | ||||
| 	KeepAlive        time.Duration | ||||
| 	Server           string | ||||
|  | ||||
| 	socket net.Conn | ||||
| 	pwrite chan string | ||||
| 	end    chan struct{} | ||||
|  | ||||
| 	nick        string //The nickname we want. | ||||
| 	nickcurrent string //The nickname we currently have. | ||||
| 	user        string | ||||
| 	registered  bool | ||||
| 	events      map[string]map[int]func(*Event) | ||||
|  | ||||
| 	QuitMessage string | ||||
| 	lastMessage time.Time | ||||
|  | ||||
| 	VerboseCallbackHandler bool | ||||
| 	Log                    *log.Logger | ||||
|  | ||||
| 	stopped bool | ||||
| 	quit    bool //User called Quit, do not reconnect. | ||||
| } | ||||
|  | ||||
| // A struct to represent an event. | ||||
| type Event struct { | ||||
| 	Code       string | ||||
| 	Raw        string | ||||
| 	Nick       string //<nick> | ||||
| 	Host       string //<nick>!<usr>@<host> | ||||
| 	Source     string //<host> | ||||
| 	User       string //<usr> | ||||
| 	Arguments  []string | ||||
| 	Tags       map[string]string | ||||
| 	Connection *Connection | ||||
| } | ||||
|  | ||||
| // Retrieve the last message from Event arguments. | ||||
| // This function  leaves the arguments untouched and | ||||
| // returns an empty string if there are none. | ||||
| func (e *Event) Message() string { | ||||
| 	if len(e.Arguments) == 0 { | ||||
| 		return "" | ||||
| 	} | ||||
| 	return e.Arguments[len(e.Arguments)-1] | ||||
| } | ||||
							
								
								
									
										14
									
								
								vendor/github.com/42wim/go-ircevent/irc_test_fuzz.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/42wim/go-ircevent/irc_test_fuzz.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,14 +0,0 @@ | ||||
| // +build gofuzz | ||||
|  | ||||
| package irc | ||||
|  | ||||
| func Fuzz(data []byte) int { | ||||
| 	b := bytes.NewBuffer(data) | ||||
| 	event, err := parseToEvent(b.String()) | ||||
| 	if err == nil { | ||||
| 		irc := IRC("go-eventirc", "go-eventirc") | ||||
| 		irc.RunCallbacks(event) | ||||
| 		return 1 | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
							
								
								
									
										5
									
								
								vendor/github.com/BurntSushi/toml/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/BurntSushi/toml/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| TAGS | ||||
| tags | ||||
| .*.swp | ||||
| tomlcheck/tomlcheck | ||||
| toml.test | ||||
							
								
								
									
										15
									
								
								vendor/github.com/BurntSushi/toml/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/BurntSushi/toml/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| language: go | ||||
| go: | ||||
|   - 1.1 | ||||
|   - 1.2 | ||||
|   - 1.3 | ||||
|   - 1.4 | ||||
|   - 1.5 | ||||
|   - 1.6 | ||||
|   - tip | ||||
| install: | ||||
|   - go install ./... | ||||
|   - go get github.com/BurntSushi/toml-test | ||||
| script: | ||||
|   - export PATH="$PATH:$HOME/gopath/bin" | ||||
|   - make test | ||||
							
								
								
									
										3
									
								
								vendor/github.com/BurntSushi/toml/COMPATIBLE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/BurntSushi/toml/COMPATIBLE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| Compatible with TOML version | ||||
| [v0.4.0](https://github.com/toml-lang/toml/blob/v0.4.0/versions/en/toml-v0.4.0.md) | ||||
|  | ||||
							
								
								
									
										19
									
								
								vendor/github.com/BurntSushi/toml/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/BurntSushi/toml/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| install: | ||||
| 	go install ./... | ||||
|  | ||||
| test: install | ||||
| 	go test -v | ||||
| 	toml-test toml-test-decoder | ||||
| 	toml-test -encoder toml-test-encoder | ||||
|  | ||||
| fmt: | ||||
| 	gofmt -w *.go */*.go | ||||
| 	colcheck *.go */*.go | ||||
|  | ||||
| tags: | ||||
| 	find ./ -name '*.go' -print0 | xargs -0 gotags > TAGS | ||||
|  | ||||
| push: | ||||
| 	git push origin master | ||||
| 	git push github master | ||||
|  | ||||
							
								
								
									
										218
									
								
								vendor/github.com/BurntSushi/toml/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								vendor/github.com/BurntSushi/toml/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,218 @@ | ||||
| ## TOML parser and encoder for Go with reflection | ||||
|  | ||||
| TOML stands for Tom's Obvious, Minimal Language. This Go package provides a | ||||
| reflection interface similar to Go's standard library `json` and `xml` | ||||
| packages. This package also supports the `encoding.TextUnmarshaler` and | ||||
| `encoding.TextMarshaler` interfaces so that you can define custom data | ||||
| representations. (There is an example of this below.) | ||||
|  | ||||
| Spec: https://github.com/toml-lang/toml | ||||
|  | ||||
| Compatible with TOML version | ||||
| [v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md) | ||||
|  | ||||
| Documentation: https://godoc.org/github.com/BurntSushi/toml | ||||
|  | ||||
| Installation: | ||||
|  | ||||
| ```bash | ||||
| go get github.com/BurntSushi/toml | ||||
| ``` | ||||
|  | ||||
| Try the toml validator: | ||||
|  | ||||
| ```bash | ||||
| go get github.com/BurntSushi/toml/cmd/tomlv | ||||
| tomlv some-toml-file.toml | ||||
| ``` | ||||
|  | ||||
| [](https://travis-ci.org/BurntSushi/toml) [](https://godoc.org/github.com/BurntSushi/toml) | ||||
|  | ||||
| ### Testing | ||||
|  | ||||
| This package passes all tests in | ||||
| [toml-test](https://github.com/BurntSushi/toml-test) for both the decoder | ||||
| and the encoder. | ||||
|  | ||||
| ### Examples | ||||
|  | ||||
| This package works similarly to how the Go standard library handles `XML` | ||||
| and `JSON`. Namely, data is loaded into Go values via reflection. | ||||
|  | ||||
| For the simplest example, consider some TOML file as just a list of keys | ||||
| and values: | ||||
|  | ||||
| ```toml | ||||
| Age = 25 | ||||
| Cats = [ "Cauchy", "Plato" ] | ||||
| Pi = 3.14 | ||||
| Perfection = [ 6, 28, 496, 8128 ] | ||||
| DOB = 1987-07-05T05:45:00Z | ||||
| ``` | ||||
|  | ||||
| Which could be defined in Go as: | ||||
|  | ||||
| ```go | ||||
| type Config struct { | ||||
|   Age int | ||||
|   Cats []string | ||||
|   Pi float64 | ||||
|   Perfection []int | ||||
|   DOB time.Time // requires `import time` | ||||
| } | ||||
| ``` | ||||
|  | ||||
| And then decoded with: | ||||
|  | ||||
| ```go | ||||
| var conf Config | ||||
| if _, err := toml.Decode(tomlData, &conf); err != nil { | ||||
|   // handle error | ||||
| } | ||||
| ``` | ||||
|  | ||||
| You can also use struct tags if your struct field name doesn't map to a TOML | ||||
| key value directly: | ||||
|  | ||||
| ```toml | ||||
| some_key_NAME = "wat" | ||||
| ``` | ||||
|  | ||||
| ```go | ||||
| type TOML struct { | ||||
|   ObscureKey string `toml:"some_key_NAME"` | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### Using the `encoding.TextUnmarshaler` interface | ||||
|  | ||||
| Here's an example that automatically parses duration strings into | ||||
| `time.Duration` values: | ||||
|  | ||||
| ```toml | ||||
| [[song]] | ||||
| name = "Thunder Road" | ||||
| duration = "4m49s" | ||||
|  | ||||
| [[song]] | ||||
| name = "Stairway to Heaven" | ||||
| duration = "8m03s" | ||||
| ``` | ||||
|  | ||||
| Which can be decoded with: | ||||
|  | ||||
| ```go | ||||
| type song struct { | ||||
|   Name     string | ||||
|   Duration duration | ||||
| } | ||||
| type songs struct { | ||||
|   Song []song | ||||
| } | ||||
| var favorites songs | ||||
| if _, err := toml.Decode(blob, &favorites); err != nil { | ||||
|   log.Fatal(err) | ||||
| } | ||||
|  | ||||
| for _, s := range favorites.Song { | ||||
|   fmt.Printf("%s (%s)\n", s.Name, s.Duration) | ||||
| } | ||||
| ``` | ||||
|  | ||||
| And you'll also need a `duration` type that satisfies the | ||||
| `encoding.TextUnmarshaler` interface: | ||||
|  | ||||
| ```go | ||||
| type duration struct { | ||||
| 	time.Duration | ||||
| } | ||||
|  | ||||
| func (d *duration) UnmarshalText(text []byte) error { | ||||
| 	var err error | ||||
| 	d.Duration, err = time.ParseDuration(string(text)) | ||||
| 	return err | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### More complex usage | ||||
|  | ||||
| Here's an example of how to load the example from the official spec page: | ||||
|  | ||||
| ```toml | ||||
| # This is a TOML document. Boom. | ||||
|  | ||||
| title = "TOML Example" | ||||
|  | ||||
| [owner] | ||||
| name = "Tom Preston-Werner" | ||||
| organization = "GitHub" | ||||
| bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." | ||||
| dob = 1979-05-27T07:32:00Z # First class dates? Why not? | ||||
|  | ||||
| [database] | ||||
| server = "192.168.1.1" | ||||
| ports = [ 8001, 8001, 8002 ] | ||||
| connection_max = 5000 | ||||
| enabled = true | ||||
|  | ||||
| [servers] | ||||
|  | ||||
|   # You can indent as you please. Tabs or spaces. TOML don't care. | ||||
|   [servers.alpha] | ||||
|   ip = "10.0.0.1" | ||||
|   dc = "eqdc10" | ||||
|  | ||||
|   [servers.beta] | ||||
|   ip = "10.0.0.2" | ||||
|   dc = "eqdc10" | ||||
|  | ||||
| [clients] | ||||
| data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it | ||||
|  | ||||
| # Line breaks are OK when inside arrays | ||||
| hosts = [ | ||||
|   "alpha", | ||||
|   "omega" | ||||
| ] | ||||
| ``` | ||||
|  | ||||
| And the corresponding Go types are: | ||||
|  | ||||
| ```go | ||||
| type tomlConfig struct { | ||||
| 	Title string | ||||
| 	Owner ownerInfo | ||||
| 	DB database `toml:"database"` | ||||
| 	Servers map[string]server | ||||
| 	Clients clients | ||||
| } | ||||
|  | ||||
| type ownerInfo struct { | ||||
| 	Name string | ||||
| 	Org string `toml:"organization"` | ||||
| 	Bio string | ||||
| 	DOB time.Time | ||||
| } | ||||
|  | ||||
| type database struct { | ||||
| 	Server string | ||||
| 	Ports []int | ||||
| 	ConnMax int `toml:"connection_max"` | ||||
| 	Enabled bool | ||||
| } | ||||
|  | ||||
| type server struct { | ||||
| 	IP string | ||||
| 	DC string | ||||
| } | ||||
|  | ||||
| type clients struct { | ||||
| 	Data [][]interface{} | ||||
| 	Hosts []string | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Note that a case insensitive match will be tried if an exact match can't be | ||||
| found. | ||||
|  | ||||
| A working example of the above can be found in `_examples/example.{go,toml}`. | ||||
							
								
								
									
										90
									
								
								vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/main.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										90
									
								
								vendor/github.com/BurntSushi/toml/cmd/toml-test-decoder/main.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,90 +0,0 @@ | ||||
| // Command toml-test-decoder satisfies the toml-test interface for testing | ||||
| // TOML decoders. Namely, it accepts TOML on stdin and outputs JSON on stdout. | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/BurntSushi/toml" | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	log.SetFlags(0) | ||||
|  | ||||
| 	flag.Usage = usage | ||||
| 	flag.Parse() | ||||
| } | ||||
|  | ||||
| func usage() { | ||||
| 	log.Printf("Usage: %s < toml-file\n", path.Base(os.Args[0])) | ||||
| 	flag.PrintDefaults() | ||||
|  | ||||
| 	os.Exit(1) | ||||
| } | ||||
|  | ||||
| func main() { | ||||
| 	if flag.NArg() != 0 { | ||||
| 		flag.Usage() | ||||
| 	} | ||||
|  | ||||
| 	var tmp interface{} | ||||
| 	if _, err := toml.DecodeReader(os.Stdin, &tmp); err != nil { | ||||
| 		log.Fatalf("Error decoding TOML: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	typedTmp := translate(tmp) | ||||
| 	if err := json.NewEncoder(os.Stdout).Encode(typedTmp); err != nil { | ||||
| 		log.Fatalf("Error encoding JSON: %s", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func translate(tomlData interface{}) interface{} { | ||||
| 	switch orig := tomlData.(type) { | ||||
| 	case map[string]interface{}: | ||||
| 		typed := make(map[string]interface{}, len(orig)) | ||||
| 		for k, v := range orig { | ||||
| 			typed[k] = translate(v) | ||||
| 		} | ||||
| 		return typed | ||||
| 	case []map[string]interface{}: | ||||
| 		typed := make([]map[string]interface{}, len(orig)) | ||||
| 		for i, v := range orig { | ||||
| 			typed[i] = translate(v).(map[string]interface{}) | ||||
| 		} | ||||
| 		return typed | ||||
| 	case []interface{}: | ||||
| 		typed := make([]interface{}, len(orig)) | ||||
| 		for i, v := range orig { | ||||
| 			typed[i] = translate(v) | ||||
| 		} | ||||
|  | ||||
| 		// We don't really need to tag arrays, but let's be future proof. | ||||
| 		// (If TOML ever supports tuples, we'll need this.) | ||||
| 		return tag("array", typed) | ||||
| 	case time.Time: | ||||
| 		return tag("datetime", orig.Format("2006-01-02T15:04:05Z")) | ||||
| 	case bool: | ||||
| 		return tag("bool", fmt.Sprintf("%v", orig)) | ||||
| 	case int64: | ||||
| 		return tag("integer", fmt.Sprintf("%d", orig)) | ||||
| 	case float64: | ||||
| 		return tag("float", fmt.Sprintf("%v", orig)) | ||||
| 	case string: | ||||
| 		return tag("string", orig) | ||||
| 	} | ||||
|  | ||||
| 	panic(fmt.Sprintf("Unknown type: %T", tomlData)) | ||||
| } | ||||
|  | ||||
| func tag(typeName string, data interface{}) map[string]interface{} { | ||||
| 	return map[string]interface{}{ | ||||
| 		"type":  typeName, | ||||
| 		"value": data, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										131
									
								
								vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/main.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										131
									
								
								vendor/github.com/BurntSushi/toml/cmd/toml-test-encoder/main.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,131 +0,0 @@ | ||||
| // Command toml-test-encoder satisfies the toml-test interface for testing | ||||
| // TOML encoders. Namely, it accepts JSON on stdin and outputs TOML on stdout. | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"flag" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/BurntSushi/toml" | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	log.SetFlags(0) | ||||
|  | ||||
| 	flag.Usage = usage | ||||
| 	flag.Parse() | ||||
| } | ||||
|  | ||||
| func usage() { | ||||
| 	log.Printf("Usage: %s < json-file\n", path.Base(os.Args[0])) | ||||
| 	flag.PrintDefaults() | ||||
|  | ||||
| 	os.Exit(1) | ||||
| } | ||||
|  | ||||
| func main() { | ||||
| 	if flag.NArg() != 0 { | ||||
| 		flag.Usage() | ||||
| 	} | ||||
|  | ||||
| 	var tmp interface{} | ||||
| 	if err := json.NewDecoder(os.Stdin).Decode(&tmp); err != nil { | ||||
| 		log.Fatalf("Error decoding JSON: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	tomlData := translate(tmp) | ||||
| 	if err := toml.NewEncoder(os.Stdout).Encode(tomlData); err != nil { | ||||
| 		log.Fatalf("Error encoding TOML: %s", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func translate(typedJson interface{}) interface{} { | ||||
| 	switch v := typedJson.(type) { | ||||
| 	case map[string]interface{}: | ||||
| 		if len(v) == 2 && in("type", v) && in("value", v) { | ||||
| 			return untag(v) | ||||
| 		} | ||||
| 		m := make(map[string]interface{}, len(v)) | ||||
| 		for k, v2 := range v { | ||||
| 			m[k] = translate(v2) | ||||
| 		} | ||||
| 		return m | ||||
| 	case []interface{}: | ||||
| 		tabArray := make([]map[string]interface{}, len(v)) | ||||
| 		for i := range v { | ||||
| 			if m, ok := translate(v[i]).(map[string]interface{}); ok { | ||||
| 				tabArray[i] = m | ||||
| 			} else { | ||||
| 				log.Fatalf("JSON arrays may only contain objects. This " + | ||||
| 					"corresponds to only tables being allowed in " + | ||||
| 					"TOML table arrays.") | ||||
| 			} | ||||
| 		} | ||||
| 		return tabArray | ||||
| 	} | ||||
| 	log.Fatalf("Unrecognized JSON format '%T'.", typedJson) | ||||
| 	panic("unreachable") | ||||
| } | ||||
|  | ||||
| func untag(typed map[string]interface{}) interface{} { | ||||
| 	t := typed["type"].(string) | ||||
| 	v := typed["value"] | ||||
| 	switch t { | ||||
| 	case "string": | ||||
| 		return v.(string) | ||||
| 	case "integer": | ||||
| 		v := v.(string) | ||||
| 		n, err := strconv.Atoi(v) | ||||
| 		if err != nil { | ||||
| 			log.Fatalf("Could not parse '%s' as integer: %s", v, err) | ||||
| 		} | ||||
| 		return n | ||||
| 	case "float": | ||||
| 		v := v.(string) | ||||
| 		f, err := strconv.ParseFloat(v, 64) | ||||
| 		if err != nil { | ||||
| 			log.Fatalf("Could not parse '%s' as float64: %s", v, err) | ||||
| 		} | ||||
| 		return f | ||||
| 	case "datetime": | ||||
| 		v := v.(string) | ||||
| 		t, err := time.Parse("2006-01-02T15:04:05Z", v) | ||||
| 		if err != nil { | ||||
| 			log.Fatalf("Could not parse '%s' as a datetime: %s", v, err) | ||||
| 		} | ||||
| 		return t | ||||
| 	case "bool": | ||||
| 		v := v.(string) | ||||
| 		switch v { | ||||
| 		case "true": | ||||
| 			return true | ||||
| 		case "false": | ||||
| 			return false | ||||
| 		} | ||||
| 		log.Fatalf("Could not parse '%s' as a boolean.", v) | ||||
| 	case "array": | ||||
| 		v := v.([]interface{}) | ||||
| 		array := make([]interface{}, len(v)) | ||||
| 		for i := range v { | ||||
| 			if m, ok := v[i].(map[string]interface{}); ok { | ||||
| 				array[i] = untag(m) | ||||
| 			} else { | ||||
| 				log.Fatalf("Arrays may only contain other arrays or "+ | ||||
| 					"primitive values, but found a '%T'.", m) | ||||
| 			} | ||||
| 		} | ||||
| 		return array | ||||
| 	} | ||||
| 	log.Fatalf("Unrecognized tag type '%s'.", t) | ||||
| 	panic("unreachable") | ||||
| } | ||||
|  | ||||
| func in(key string, m map[string]interface{}) bool { | ||||
| 	_, ok := m[key] | ||||
| 	return ok | ||||
| } | ||||
							
								
								
									
										61
									
								
								vendor/github.com/BurntSushi/toml/cmd/tomlv/main.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										61
									
								
								vendor/github.com/BurntSushi/toml/cmd/tomlv/main.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,61 +0,0 @@ | ||||
| // Command tomlv validates TOML documents and prints each key's type. | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"strings" | ||||
| 	"text/tabwriter" | ||||
|  | ||||
| 	"github.com/BurntSushi/toml" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	flagTypes = false | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	log.SetFlags(0) | ||||
|  | ||||
| 	flag.BoolVar(&flagTypes, "types", flagTypes, | ||||
| 		"When set, the types of every defined key will be shown.") | ||||
|  | ||||
| 	flag.Usage = usage | ||||
| 	flag.Parse() | ||||
| } | ||||
|  | ||||
| func usage() { | ||||
| 	log.Printf("Usage: %s toml-file [ toml-file ... ]\n", | ||||
| 		path.Base(os.Args[0])) | ||||
| 	flag.PrintDefaults() | ||||
|  | ||||
| 	os.Exit(1) | ||||
| } | ||||
|  | ||||
| func main() { | ||||
| 	if flag.NArg() < 1 { | ||||
| 		flag.Usage() | ||||
| 	} | ||||
| 	for _, f := range flag.Args() { | ||||
| 		var tmp interface{} | ||||
| 		md, err := toml.DecodeFile(f, &tmp) | ||||
| 		if err != nil { | ||||
| 			log.Fatalf("Error in '%s': %s", f, err) | ||||
| 		} | ||||
| 		if flagTypes { | ||||
| 			printTypes(md) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func printTypes(md toml.MetaData) { | ||||
| 	tabw := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) | ||||
| 	for _, key := range md.Keys() { | ||||
| 		fmt.Fprintf(tabw, "%s%s\t%s\n", | ||||
| 			strings.Repeat("    ", len(key)-1), key, md.Type(key...)) | ||||
| 	} | ||||
| 	tabw.Flush() | ||||
| } | ||||
							
								
								
									
										1
									
								
								vendor/github.com/BurntSushi/toml/session.vim
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/BurntSushi/toml/session.vim
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| au BufWritePost *.go silent!make tags > /dev/null 2>&1 | ||||
							
								
								
									
										138
									
								
								vendor/github.com/GeertJohan/go.rice/appended.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										138
									
								
								vendor/github.com/GeertJohan/go.rice/appended.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,138 +0,0 @@ | ||||
| package rice | ||||
|  | ||||
| import ( | ||||
| 	"archive/zip" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/daaku/go.zipexe" | ||||
| 	"github.com/kardianos/osext" | ||||
| ) | ||||
|  | ||||
| // appendedBox defines an appended box | ||||
| type appendedBox struct { | ||||
| 	Name  string                   // box name | ||||
| 	Files map[string]*appendedFile // appended files (*zip.File) by full path | ||||
| } | ||||
|  | ||||
| type appendedFile struct { | ||||
| 	zipFile  *zip.File | ||||
| 	dir      bool | ||||
| 	dirInfo  *appendedDirInfo | ||||
| 	children []*appendedFile | ||||
| 	content  []byte | ||||
| } | ||||
|  | ||||
| // appendedBoxes is a public register of appendes boxes | ||||
| var appendedBoxes = make(map[string]*appendedBox) | ||||
|  | ||||
| func init() { | ||||
| 	// find if exec is appended | ||||
| 	thisFile, err := osext.Executable() | ||||
| 	if err != nil { | ||||
| 		return // not appended or cant find self executable | ||||
| 	} | ||||
| 	closer, rd, err := zipexe.OpenCloser(thisFile) | ||||
| 	if err != nil { | ||||
| 		return // not appended | ||||
| 	} | ||||
| 	defer closer.Close() | ||||
|  | ||||
| 	for _, f := range rd.File { | ||||
| 		// get box and file name from f.Name | ||||
| 		fileParts := strings.SplitN(strings.TrimLeft(filepath.ToSlash(f.Name), "/"), "/", 2) | ||||
| 		boxName := fileParts[0] | ||||
| 		var fileName string | ||||
| 		if len(fileParts) > 1 { | ||||
| 			fileName = fileParts[1] | ||||
| 		} | ||||
|  | ||||
| 		// find box or create new one if doesn't exist | ||||
| 		box := appendedBoxes[boxName] | ||||
| 		if box == nil { | ||||
| 			box = &appendedBox{ | ||||
| 				Name:  boxName, | ||||
| 				Files: make(map[string]*appendedFile), | ||||
| 			} | ||||
| 			appendedBoxes[boxName] = box | ||||
| 		} | ||||
|  | ||||
| 		// create and add file to box | ||||
| 		af := &appendedFile{ | ||||
| 			zipFile: f, | ||||
| 		} | ||||
| 		if f.Comment == "dir" { | ||||
| 			af.dir = true | ||||
| 			af.dirInfo = &appendedDirInfo{ | ||||
| 				name: filepath.Base(af.zipFile.Name), | ||||
| 				//++ TODO: use zip modtime when that is set correctly: af.zipFile.ModTime() | ||||
| 				time: time.Now(), | ||||
| 			} | ||||
| 		} else { | ||||
| 			// this is a file, we need it's contents so we can create a bytes.Reader when the file is opened | ||||
| 			// make a new byteslice | ||||
| 			af.content = make([]byte, af.zipFile.FileInfo().Size()) | ||||
| 			// ignore reading empty files from zip (empty file still is a valid file to be read though!) | ||||
| 			if len(af.content) > 0 { | ||||
| 				// open io.ReadCloser | ||||
| 				rc, err := af.zipFile.Open() | ||||
| 				if err != nil { | ||||
| 					af.content = nil // this will cause an error when the file is being opened or seeked (which is good) | ||||
| 					// TODO: it's quite blunt to just log this stuff. but this is in init, so rice.Debug can't be changed yet.. | ||||
| 					log.Printf("error opening appended file %s: %v", af.zipFile.Name, err) | ||||
| 				} else { | ||||
| 					_, err = rc.Read(af.content) | ||||
| 					rc.Close() | ||||
| 					if err != nil { | ||||
| 						af.content = nil // this will cause an error when the file is being opened or seeked (which is good) | ||||
| 						// TODO: it's quite blunt to just log this stuff. but this is in init, so rice.Debug can't be changed yet.. | ||||
| 						log.Printf("error reading data for appended file %s: %v", af.zipFile.Name, err) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// add appendedFile to box file list | ||||
| 		box.Files[fileName] = af | ||||
|  | ||||
| 		// add to parent dir (if any) | ||||
| 		dirName := filepath.Dir(fileName) | ||||
| 		if dirName == "." { | ||||
| 			dirName = "" | ||||
| 		} | ||||
| 		if fileName != "" { // don't make box root dir a child of itself | ||||
| 			if dir := box.Files[dirName]; dir != nil { | ||||
| 				dir.children = append(dir.children, af) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // implements os.FileInfo. | ||||
| // used for Readdir() | ||||
| type appendedDirInfo struct { | ||||
| 	name string | ||||
| 	time time.Time | ||||
| } | ||||
|  | ||||
| func (adi *appendedDirInfo) Name() string { | ||||
| 	return adi.name | ||||
| } | ||||
| func (adi *appendedDirInfo) Size() int64 { | ||||
| 	return 0 | ||||
| } | ||||
| func (adi *appendedDirInfo) Mode() os.FileMode { | ||||
| 	return os.ModeDir | ||||
| } | ||||
| func (adi *appendedDirInfo) ModTime() time.Time { | ||||
| 	return adi.time | ||||
| } | ||||
| func (adi *appendedDirInfo) IsDir() bool { | ||||
| 	return true | ||||
| } | ||||
| func (adi *appendedDirInfo) Sys() interface{} { | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										337
									
								
								vendor/github.com/GeertJohan/go.rice/box.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										337
									
								
								vendor/github.com/GeertJohan/go.rice/box.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,337 +0,0 @@ | ||||
| package rice | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/GeertJohan/go.rice/embedded" | ||||
| ) | ||||
|  | ||||
| // Box abstracts a directory for resources/files. | ||||
| // It can either load files from disk, or from embedded code (when `rice --embed` was ran). | ||||
| type Box struct { | ||||
| 	name         string | ||||
| 	absolutePath string | ||||
| 	embed        *embedded.EmbeddedBox | ||||
| 	appendd      *appendedBox | ||||
| } | ||||
|  | ||||
| var defaultLocateOrder = []LocateMethod{LocateEmbedded, LocateAppended, LocateFS} | ||||
|  | ||||
| func findBox(name string, order []LocateMethod) (*Box, error) { | ||||
| 	b := &Box{name: name} | ||||
|  | ||||
| 	// no support for absolute paths since gopath can be different on different machines. | ||||
| 	// therefore, required box must be located relative to package requiring it. | ||||
| 	if filepath.IsAbs(name) { | ||||
| 		return nil, errors.New("given name/path is absolute") | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	for _, method := range order { | ||||
| 		switch method { | ||||
| 		case LocateEmbedded: | ||||
| 			if embed := embedded.EmbeddedBoxes[name]; embed != nil { | ||||
| 				b.embed = embed | ||||
| 				return b, nil | ||||
| 			} | ||||
|  | ||||
| 		case LocateAppended: | ||||
| 			appendedBoxName := strings.Replace(name, `/`, `-`, -1) | ||||
| 			if appendd := appendedBoxes[appendedBoxName]; appendd != nil { | ||||
| 				b.appendd = appendd | ||||
| 				return b, nil | ||||
| 			} | ||||
|  | ||||
| 		case LocateFS: | ||||
| 			// resolve absolute directory path | ||||
| 			err := b.resolveAbsolutePathFromCaller() | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			// check if absolutePath exists on filesystem | ||||
| 			info, err := os.Stat(b.absolutePath) | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			// check if absolutePath is actually a directory | ||||
| 			if !info.IsDir() { | ||||
| 				err = errors.New("given name/path is not a directory") | ||||
| 				continue | ||||
| 			} | ||||
| 			return b, nil | ||||
| 		case LocateWorkingDirectory: | ||||
| 			// resolve absolute directory path | ||||
| 			err := b.resolveAbsolutePathFromWorkingDirectory() | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			// check if absolutePath exists on filesystem | ||||
| 			info, err := os.Stat(b.absolutePath) | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			// check if absolutePath is actually a directory | ||||
| 			if !info.IsDir() { | ||||
| 				err = errors.New("given name/path is not a directory") | ||||
| 				continue | ||||
| 			} | ||||
| 			return b, nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err == nil { | ||||
| 		err = fmt.Errorf("could not locate box %q", name) | ||||
| 	} | ||||
|  | ||||
| 	return nil, err | ||||
| } | ||||
|  | ||||
| // FindBox returns a Box instance for given name. | ||||
| // When the given name is a relative path, it's base path will be the calling pkg/cmd's source root. | ||||
| // When the given name is absolute, it's absolute. derp. | ||||
| // Make sure the path doesn't contain any sensitive information as it might be placed into generated go source (embedded). | ||||
| func FindBox(name string) (*Box, error) { | ||||
| 	return findBox(name, defaultLocateOrder) | ||||
| } | ||||
|  | ||||
| // MustFindBox returns a Box instance for given name, like FindBox does. | ||||
| // It does not return an error, instead it panics when an error occurs. | ||||
| func MustFindBox(name string) *Box { | ||||
| 	box, err := findBox(name, defaultLocateOrder) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return box | ||||
| } | ||||
|  | ||||
| // This is injected as a mutable function literal so that we can mock it out in | ||||
| // tests and return a fixed test file. | ||||
| var resolveAbsolutePathFromCaller = func(name string, nStackFrames int) (string, error) { | ||||
| 	_, callingGoFile, _, ok := runtime.Caller(nStackFrames) | ||||
| 	if !ok { | ||||
| 		return "", errors.New("couldn't find caller on stack") | ||||
| 	} | ||||
|  | ||||
| 	// resolve to proper path | ||||
| 	pkgDir := filepath.Dir(callingGoFile) | ||||
| 	// fix for go cover | ||||
| 	const coverPath = "_test/_obj_test" | ||||
| 	if !filepath.IsAbs(pkgDir) { | ||||
| 		if i := strings.Index(pkgDir, coverPath); i >= 0 { | ||||
| 			pkgDir = pkgDir[:i] + pkgDir[i+len(coverPath):]            // remove coverPath | ||||
| 			pkgDir = filepath.Join(os.Getenv("GOPATH"), "src", pkgDir) // make absolute | ||||
| 		} | ||||
| 	} | ||||
| 	return filepath.Join(pkgDir, name), nil | ||||
| } | ||||
|  | ||||
| func (b *Box) resolveAbsolutePathFromCaller() error { | ||||
| 	path, err := resolveAbsolutePathFromCaller(b.name, 4) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	b.absolutePath = path | ||||
| 	return nil | ||||
|  | ||||
| } | ||||
|  | ||||
| func (b *Box) resolveAbsolutePathFromWorkingDirectory() error { | ||||
| 	path, err := os.Getwd() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	b.absolutePath = filepath.Join(path, b.name) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // IsEmbedded indicates wether this box was embedded into the application | ||||
| func (b *Box) IsEmbedded() bool { | ||||
| 	return b.embed != nil | ||||
| } | ||||
|  | ||||
| // IsAppended indicates wether this box was appended to the application | ||||
| func (b *Box) IsAppended() bool { | ||||
| 	return b.appendd != nil | ||||
| } | ||||
|  | ||||
| // Time returns how actual the box is. | ||||
| // When the box is embedded, it's value is saved in the embedding code. | ||||
| // When the box is live, this methods returns time.Now() | ||||
| func (b *Box) Time() time.Time { | ||||
| 	if b.IsEmbedded() { | ||||
| 		return b.embed.Time | ||||
| 	} | ||||
|  | ||||
| 	//++ TODO: return time for appended box | ||||
|  | ||||
| 	return time.Now() | ||||
| } | ||||
|  | ||||
| // Open opens a File from the box | ||||
| // If there is an error, it will be of type *os.PathError. | ||||
| func (b *Box) Open(name string) (*File, error) { | ||||
| 	if Debug { | ||||
| 		fmt.Printf("Open(%s)\n", name) | ||||
| 	} | ||||
|  | ||||
| 	if b.IsEmbedded() { | ||||
| 		if Debug { | ||||
| 			fmt.Println("Box is embedded") | ||||
| 		} | ||||
|  | ||||
| 		// trim prefix (paths are relative to box) | ||||
| 		name = strings.TrimLeft(name, "/") | ||||
| 		if Debug { | ||||
| 			fmt.Printf("Trying %s\n", name) | ||||
| 		} | ||||
|  | ||||
| 		// search for file | ||||
| 		ef := b.embed.Files[name] | ||||
| 		if ef == nil { | ||||
| 			if Debug { | ||||
| 				fmt.Println("Didn't find file in embed") | ||||
| 			} | ||||
| 			// file not found, try dir | ||||
| 			ed := b.embed.Dirs[name] | ||||
| 			if ed == nil { | ||||
| 				if Debug { | ||||
| 					fmt.Println("Didn't find dir in embed") | ||||
| 				} | ||||
| 				// dir not found, error out | ||||
| 				return nil, &os.PathError{ | ||||
| 					Op:   "open", | ||||
| 					Path: name, | ||||
| 					Err:  os.ErrNotExist, | ||||
| 				} | ||||
| 			} | ||||
| 			if Debug { | ||||
| 				fmt.Println("Found dir. Returning virtual dir") | ||||
| 			} | ||||
| 			vd := newVirtualDir(ed) | ||||
| 			return &File{virtualD: vd}, nil | ||||
| 		} | ||||
|  | ||||
| 		// box is embedded | ||||
| 		if Debug { | ||||
| 			fmt.Println("Found file. Returning virtual file") | ||||
| 		} | ||||
| 		vf := newVirtualFile(ef) | ||||
| 		return &File{virtualF: vf}, nil | ||||
| 	} | ||||
|  | ||||
| 	if b.IsAppended() { | ||||
| 		// trim prefix (paths are relative to box) | ||||
| 		name = strings.TrimLeft(name, "/") | ||||
|  | ||||
| 		// search for file | ||||
| 		appendedFile := b.appendd.Files[name] | ||||
| 		if appendedFile == nil { | ||||
| 			return nil, &os.PathError{ | ||||
| 				Op:   "open", | ||||
| 				Path: name, | ||||
| 				Err:  os.ErrNotExist, | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// create new file | ||||
| 		f := &File{ | ||||
| 			appendedF: appendedFile, | ||||
| 		} | ||||
|  | ||||
| 		// if this file is a directory, we want to be able to read and seek | ||||
| 		if !appendedFile.dir { | ||||
| 			// looks like malformed data in zip, error now | ||||
| 			if appendedFile.content == nil { | ||||
| 				return nil, &os.PathError{ | ||||
| 					Op:   "open", | ||||
| 					Path: "name", | ||||
| 					Err:  errors.New("error reading data from zip file"), | ||||
| 				} | ||||
| 			} | ||||
| 			// create new bytes.Reader | ||||
| 			f.appendedFileReader = bytes.NewReader(appendedFile.content) | ||||
| 		} | ||||
|  | ||||
| 		// all done | ||||
| 		return f, nil | ||||
| 	} | ||||
|  | ||||
| 	// perform os open | ||||
| 	if Debug { | ||||
| 		fmt.Printf("Using os.Open(%s)", filepath.Join(b.absolutePath, name)) | ||||
| 	} | ||||
| 	file, err := os.Open(filepath.Join(b.absolutePath, name)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &File{realF: file}, nil | ||||
| } | ||||
|  | ||||
| // Bytes returns the content of the file with given name as []byte. | ||||
| func (b *Box) Bytes(name string) ([]byte, error) { | ||||
| 	file, err := b.Open(name) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer file.Close() | ||||
|  | ||||
| 	content, err := ioutil.ReadAll(file) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return content, nil | ||||
| } | ||||
|  | ||||
| // MustBytes returns the content of the file with given name as []byte. | ||||
| // panic's on error. | ||||
| func (b *Box) MustBytes(name string) []byte { | ||||
| 	bts, err := b.Bytes(name) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return bts | ||||
| } | ||||
|  | ||||
| // String returns the content of the file with given name as string. | ||||
| func (b *Box) String(name string) (string, error) { | ||||
| 	// check if box is embedded, optimized fast path | ||||
| 	if b.IsEmbedded() { | ||||
| 		// find file in embed | ||||
| 		ef := b.embed.Files[name] | ||||
| 		if ef == nil { | ||||
| 			return "", os.ErrNotExist | ||||
| 		} | ||||
| 		// return as string | ||||
| 		return ef.Content, nil | ||||
| 	} | ||||
|  | ||||
| 	bts, err := b.Bytes(name) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return string(bts), nil | ||||
| } | ||||
|  | ||||
| // MustString returns the content of the file with given name as string. | ||||
| // panic's on error. | ||||
| func (b *Box) MustString(name string) string { | ||||
| 	str, err := b.String(name) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return str | ||||
| } | ||||
|  | ||||
| // Name returns the name of the box | ||||
| func (b *Box) Name() string { | ||||
| 	return b.name | ||||
| } | ||||
							
								
								
									
										39
									
								
								vendor/github.com/GeertJohan/go.rice/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/GeertJohan/go.rice/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,39 +0,0 @@ | ||||
| package rice | ||||
|  | ||||
| // LocateMethod defines how a box is located. | ||||
| type LocateMethod int | ||||
|  | ||||
| const ( | ||||
| 	LocateFS               = LocateMethod(iota) // Locate on the filesystem according to package path. | ||||
| 	LocateAppended                              // Locate boxes appended to the executable. | ||||
| 	LocateEmbedded                              // Locate embedded boxes. | ||||
| 	LocateWorkingDirectory                      // Locate on the binary working directory | ||||
| ) | ||||
|  | ||||
| // Config allows customizing the box lookup behavior. | ||||
| type Config struct { | ||||
| 	// LocateOrder defines the priority order that boxes are searched for. By | ||||
| 	// default, the package global FindBox searches for embedded boxes first, | ||||
| 	// then appended boxes, and then finally boxes on the filesystem.  That | ||||
| 	// search order may be customized by provided the ordered list here. Leaving | ||||
| 	// out a particular method will omit that from the search space. For | ||||
| 	// example, []LocateMethod{LocateEmbedded, LocateAppended} will never search | ||||
| 	// the filesystem for boxes. | ||||
| 	LocateOrder []LocateMethod | ||||
| } | ||||
|  | ||||
| // FindBox searches for boxes using the LocateOrder of the config. | ||||
| func (c *Config) FindBox(boxName string) (*Box, error) { | ||||
| 	return findBox(boxName, c.LocateOrder) | ||||
| } | ||||
|  | ||||
| // MustFindBox searches for boxes using the LocateOrder of the config, like | ||||
| // FindBox does.  It does not return an error, instead it panics when an error | ||||
| // occurs. | ||||
| func (c *Config) MustFindBox(boxName string) *Box { | ||||
| 	box, err := findBox(boxName, c.LocateOrder) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return box | ||||
| } | ||||
							
								
								
									
										4
									
								
								vendor/github.com/GeertJohan/go.rice/debug.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/GeertJohan/go.rice/debug.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +0,0 @@ | ||||
| package rice | ||||
|  | ||||
| // Debug can be set to true to enable debugging. | ||||
| var Debug = false | ||||
							
								
								
									
										90
									
								
								vendor/github.com/GeertJohan/go.rice/embedded.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										90
									
								
								vendor/github.com/GeertJohan/go.rice/embedded.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,90 +0,0 @@ | ||||
| package rice | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/GeertJohan/go.rice/embedded" | ||||
| ) | ||||
|  | ||||
| // re-type to make exported methods invisible to user (godoc) | ||||
| // they're not required for the user | ||||
| // embeddedDirInfo implements os.FileInfo | ||||
| type embeddedDirInfo embedded.EmbeddedDir | ||||
|  | ||||
| // Name returns the base name of the directory | ||||
| // (implementing os.FileInfo) | ||||
| func (ed *embeddedDirInfo) Name() string { | ||||
| 	return ed.Filename | ||||
| } | ||||
|  | ||||
| // Size always returns 0 | ||||
| // (implementing os.FileInfo) | ||||
| func (ed *embeddedDirInfo) Size() int64 { | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| // Mode returns the file mode bits | ||||
| // (implementing os.FileInfo) | ||||
| func (ed *embeddedDirInfo) Mode() os.FileMode { | ||||
| 	return os.FileMode(0555 | os.ModeDir) // dr-xr-xr-x | ||||
| } | ||||
|  | ||||
| // ModTime returns the modification time | ||||
| // (implementing os.FileInfo) | ||||
| func (ed *embeddedDirInfo) ModTime() time.Time { | ||||
| 	return ed.DirModTime | ||||
| } | ||||
|  | ||||
| // IsDir returns the abbreviation for Mode().IsDir() (always true) | ||||
| // (implementing os.FileInfo) | ||||
| func (ed *embeddedDirInfo) IsDir() bool { | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // Sys returns the underlying data source (always nil) | ||||
| // (implementing os.FileInfo) | ||||
| func (ed *embeddedDirInfo) Sys() interface{} { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // re-type to make exported methods invisible to user (godoc) | ||||
| // they're not required for the user | ||||
| // embeddedFileInfo implements os.FileInfo | ||||
| type embeddedFileInfo embedded.EmbeddedFile | ||||
|  | ||||
| // Name returns the base name of the file | ||||
| // (implementing os.FileInfo) | ||||
| func (ef *embeddedFileInfo) Name() string { | ||||
| 	return ef.Filename | ||||
| } | ||||
|  | ||||
| // Size returns the length in bytes for regular files; system-dependent for others | ||||
| // (implementing os.FileInfo) | ||||
| func (ef *embeddedFileInfo) Size() int64 { | ||||
| 	return int64(len(ef.Content)) | ||||
| } | ||||
|  | ||||
| // Mode returns the file mode bits | ||||
| // (implementing os.FileInfo) | ||||
| func (ef *embeddedFileInfo) Mode() os.FileMode { | ||||
| 	return os.FileMode(0555) // r-xr-xr-x | ||||
| } | ||||
|  | ||||
| // ModTime returns the modification time | ||||
| // (implementing os.FileInfo) | ||||
| func (ef *embeddedFileInfo) ModTime() time.Time { | ||||
| 	return ef.FileModTime | ||||
| } | ||||
|  | ||||
| // IsDir returns the abbreviation for Mode().IsDir() (always false) | ||||
| // (implementing os.FileInfo) | ||||
| func (ef *embeddedFileInfo) IsDir() bool { | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Sys returns the underlying data source (always nil) | ||||
| // (implementing os.FileInfo) | ||||
| func (ef *embeddedFileInfo) Sys() interface{} { | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										80
									
								
								vendor/github.com/GeertJohan/go.rice/embedded/embedded.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										80
									
								
								vendor/github.com/GeertJohan/go.rice/embedded/embedded.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,80 +0,0 @@ | ||||
| // Package embedded defines embedded data types that are shared between the go.rice package and generated code. | ||||
| package embedded | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	EmbedTypeGo   = 0 | ||||
| 	EmbedTypeSyso = 1 | ||||
| ) | ||||
|  | ||||
| // EmbeddedBox defines an embedded box | ||||
| type EmbeddedBox struct { | ||||
| 	Name      string                   // box name | ||||
| 	Time      time.Time                // embed time | ||||
| 	EmbedType int                      // kind of embedding | ||||
| 	Files     map[string]*EmbeddedFile // ALL embedded files by full path | ||||
| 	Dirs      map[string]*EmbeddedDir  // ALL embedded dirs by full path | ||||
| } | ||||
|  | ||||
| // Link creates the ChildDirs and ChildFiles links in all EmbeddedDir's | ||||
| func (e *EmbeddedBox) Link() { | ||||
| 	for path, ed := range e.Dirs { | ||||
| 		fmt.Println(path) | ||||
| 		ed.ChildDirs = make([]*EmbeddedDir, 0) | ||||
| 		ed.ChildFiles = make([]*EmbeddedFile, 0) | ||||
| 	} | ||||
| 	for path, ed := range e.Dirs { | ||||
| 		parentDirpath, _ := filepath.Split(path) | ||||
| 		if strings.HasSuffix(parentDirpath, "/") { | ||||
| 			parentDirpath = parentDirpath[:len(parentDirpath)-1] | ||||
| 		} | ||||
| 		parentDir := e.Dirs[parentDirpath] | ||||
| 		if parentDir == nil { | ||||
| 			panic("parentDir `" + parentDirpath + "` is missing in embedded box") | ||||
| 		} | ||||
| 		parentDir.ChildDirs = append(parentDir.ChildDirs, ed) | ||||
| 	} | ||||
| 	for path, ef := range e.Files { | ||||
| 		dirpath, _ := filepath.Split(path) | ||||
| 		if strings.HasSuffix(dirpath, "/") { | ||||
| 			dirpath = dirpath[:len(dirpath)-1] | ||||
| 		} | ||||
| 		dir := e.Dirs[dirpath] | ||||
| 		if dir == nil { | ||||
| 			panic("dir `" + dirpath + "` is missing in embedded box") | ||||
| 		} | ||||
| 		dir.ChildFiles = append(dir.ChildFiles, ef) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // EmbeddedDir is instanced in the code generated by the rice tool and contains all necicary information about an embedded file | ||||
| type EmbeddedDir struct { | ||||
| 	Filename   string | ||||
| 	DirModTime time.Time | ||||
| 	ChildDirs  []*EmbeddedDir  // direct childs, as returned by virtualDir.Readdir() | ||||
| 	ChildFiles []*EmbeddedFile // direct childs, as returned by virtualDir.Readdir() | ||||
| } | ||||
|  | ||||
| // EmbeddedFile is instanced in the code generated by the rice tool and contains all necicary information about an embedded file | ||||
| type EmbeddedFile struct { | ||||
| 	Filename    string // filename | ||||
| 	FileModTime time.Time | ||||
| 	Content     string | ||||
| } | ||||
|  | ||||
| // EmbeddedBoxes is a public register of embedded boxes | ||||
| var EmbeddedBoxes = make(map[string]*EmbeddedBox) | ||||
|  | ||||
| // RegisterEmbeddedBox registers an EmbeddedBox | ||||
| func RegisterEmbeddedBox(name string, box *EmbeddedBox) { | ||||
| 	if _, exists := EmbeddedBoxes[name]; exists { | ||||
| 		panic(fmt.Sprintf("EmbeddedBox with name `%s` exists already", name)) | ||||
| 	} | ||||
| 	EmbeddedBoxes[name] = box | ||||
| } | ||||
							
								
								
									
										69
									
								
								vendor/github.com/GeertJohan/go.rice/example/example.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										69
									
								
								vendor/github.com/GeertJohan/go.rice/example/example.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,69 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"encoding/hex" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"text/template" | ||||
|  | ||||
| 	"github.com/GeertJohan/go.rice" | ||||
| 	"github.com/davecgh/go-spew/spew" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	conf := rice.Config{ | ||||
| 		LocateOrder: []rice.LocateMethod{rice.LocateEmbedded, rice.LocateAppended, rice.LocateFS}, | ||||
| 	} | ||||
| 	box, err := conf.FindBox("example-files") | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("error opening rice.Box: %s\n", err) | ||||
| 	} | ||||
| 	// spew.Dump(box) | ||||
|  | ||||
| 	contentString, err := box.String("file.txt") | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("could not read file contents as string: %s\n", err) | ||||
| 	} | ||||
| 	log.Printf("Read some file contents as string:\n%s\n", contentString) | ||||
|  | ||||
| 	contentBytes, err := box.Bytes("file.txt") | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("could not read file contents as byteSlice: %s\n", err) | ||||
| 	} | ||||
| 	log.Printf("Read some file contents as byteSlice:\n%s\n", hex.Dump(contentBytes)) | ||||
|  | ||||
| 	file, err := box.Open("file.txt") | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("could not open file: %s\n", err) | ||||
| 	} | ||||
| 	spew.Dump(file) | ||||
|  | ||||
| 	// find/create a rice.Box | ||||
| 	templateBox, err := rice.FindBox("example-templates") | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	// get file contents as string | ||||
| 	templateString, err := templateBox.String("message.tmpl") | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	// parse and execute the template | ||||
| 	tmplMessage, err := template.New("message").Parse(templateString) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	tmplMessage.Execute(os.Stdout, map[string]string{"Message": "Hello, world!"}) | ||||
|  | ||||
| 	http.Handle("/", http.FileServer(box.HTTPBox())) | ||||
| 	go func() { | ||||
| 		fmt.Println("Serving files on :8080, press ctrl-C to exit") | ||||
| 		err := http.ListenAndServe(":8080", nil) | ||||
| 		if err != nil { | ||||
| 			log.Fatalf("error serving files: %v", err) | ||||
| 		} | ||||
| 	}() | ||||
| 	select {} | ||||
| } | ||||
							
								
								
									
										144
									
								
								vendor/github.com/GeertJohan/go.rice/file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										144
									
								
								vendor/github.com/GeertJohan/go.rice/file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,144 +0,0 @@ | ||||
| package rice | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| ) | ||||
|  | ||||
| // File implements the io.Reader, io.Seeker, io.Closer and http.File interfaces | ||||
| type File struct { | ||||
| 	// File abstracts file methods so the user doesn't see the difference between rice.virtualFile, rice.virtualDir and os.File | ||||
| 	// TODO: maybe use internal File interface and four implementations: *os.File, appendedFile, virtualFile, virtualDir | ||||
|  | ||||
| 	// real file on disk | ||||
| 	realF *os.File | ||||
|  | ||||
| 	// when embedded (go) | ||||
| 	virtualF *virtualFile | ||||
| 	virtualD *virtualDir | ||||
|  | ||||
| 	// when appended (zip) | ||||
| 	appendedF          *appendedFile | ||||
| 	appendedFileReader *bytes.Reader | ||||
| 	// TODO: is appendedFileReader subject of races? Might need a lock here.. | ||||
| } | ||||
|  | ||||
| // Close is like (*os.File).Close() | ||||
| // Visit http://golang.org/pkg/os/#File.Close for more information | ||||
| func (f *File) Close() error { | ||||
| 	if f.appendedF != nil { | ||||
| 		if f.appendedFileReader == nil { | ||||
| 			return errors.New("already closed") | ||||
| 		} | ||||
| 		f.appendedFileReader = nil | ||||
| 		return nil | ||||
| 	} | ||||
| 	if f.virtualF != nil { | ||||
| 		return f.virtualF.close() | ||||
| 	} | ||||
| 	if f.virtualD != nil { | ||||
| 		return f.virtualD.close() | ||||
| 	} | ||||
| 	return f.realF.Close() | ||||
| } | ||||
|  | ||||
| // Stat is like (*os.File).Stat() | ||||
| // Visit http://golang.org/pkg/os/#File.Stat for more information | ||||
| func (f *File) Stat() (os.FileInfo, error) { | ||||
| 	if f.appendedF != nil { | ||||
| 		if f.appendedF.dir { | ||||
| 			return f.appendedF.dirInfo, nil | ||||
| 		} | ||||
| 		if f.appendedFileReader == nil { | ||||
| 			return nil, errors.New("file is closed") | ||||
| 		} | ||||
| 		return f.appendedF.zipFile.FileInfo(), nil | ||||
| 	} | ||||
| 	if f.virtualF != nil { | ||||
| 		return f.virtualF.stat() | ||||
| 	} | ||||
| 	if f.virtualD != nil { | ||||
| 		return f.virtualD.stat() | ||||
| 	} | ||||
| 	return f.realF.Stat() | ||||
| } | ||||
|  | ||||
| // Readdir is like (*os.File).Readdir() | ||||
| // Visit http://golang.org/pkg/os/#File.Readdir for more information | ||||
| func (f *File) Readdir(count int) ([]os.FileInfo, error) { | ||||
| 	if f.appendedF != nil { | ||||
| 		if f.appendedF.dir { | ||||
| 			fi := make([]os.FileInfo, 0, len(f.appendedF.children)) | ||||
| 			for _, childAppendedFile := range f.appendedF.children { | ||||
| 				if childAppendedFile.dir { | ||||
| 					fi = append(fi, childAppendedFile.dirInfo) | ||||
| 				} else { | ||||
| 					fi = append(fi, childAppendedFile.zipFile.FileInfo()) | ||||
| 				} | ||||
| 			} | ||||
| 			return fi, nil | ||||
| 		} | ||||
| 		//++ TODO: is os.ErrInvalid the correct error for Readdir on file? | ||||
| 		return nil, os.ErrInvalid | ||||
| 	} | ||||
| 	if f.virtualF != nil { | ||||
| 		return f.virtualF.readdir(count) | ||||
| 	} | ||||
| 	if f.virtualD != nil { | ||||
| 		return f.virtualD.readdir(count) | ||||
| 	} | ||||
| 	return f.realF.Readdir(count) | ||||
| } | ||||
|  | ||||
| // Read is like (*os.File).Read() | ||||
| // Visit http://golang.org/pkg/os/#File.Read for more information | ||||
| func (f *File) Read(bts []byte) (int, error) { | ||||
| 	if f.appendedF != nil { | ||||
| 		if f.appendedFileReader == nil { | ||||
| 			return 0, &os.PathError{ | ||||
| 				Op:   "read", | ||||
| 				Path: filepath.Base(f.appendedF.zipFile.Name), | ||||
| 				Err:  errors.New("file is closed"), | ||||
| 			} | ||||
| 		} | ||||
| 		if f.appendedF.dir { | ||||
| 			return 0, &os.PathError{ | ||||
| 				Op:   "read", | ||||
| 				Path: filepath.Base(f.appendedF.zipFile.Name), | ||||
| 				Err:  errors.New("is a directory"), | ||||
| 			} | ||||
| 		} | ||||
| 		return f.appendedFileReader.Read(bts) | ||||
| 	} | ||||
| 	if f.virtualF != nil { | ||||
| 		return f.virtualF.read(bts) | ||||
| 	} | ||||
| 	if f.virtualD != nil { | ||||
| 		return f.virtualD.read(bts) | ||||
| 	} | ||||
| 	return f.realF.Read(bts) | ||||
| } | ||||
|  | ||||
| // Seek is like (*os.File).Seek() | ||||
| // Visit http://golang.org/pkg/os/#File.Seek for more information | ||||
| func (f *File) Seek(offset int64, whence int) (int64, error) { | ||||
| 	if f.appendedF != nil { | ||||
| 		if f.appendedFileReader == nil { | ||||
| 			return 0, &os.PathError{ | ||||
| 				Op:   "seek", | ||||
| 				Path: filepath.Base(f.appendedF.zipFile.Name), | ||||
| 				Err:  errors.New("file is closed"), | ||||
| 			} | ||||
| 		} | ||||
| 		return f.appendedFileReader.Seek(offset, whence) | ||||
| 	} | ||||
| 	if f.virtualF != nil { | ||||
| 		return f.virtualF.seek(offset, whence) | ||||
| 	} | ||||
| 	if f.virtualD != nil { | ||||
| 		return f.virtualD.seek(offset, whence) | ||||
| 	} | ||||
| 	return f.realF.Seek(offset, whence) | ||||
| } | ||||
							
								
								
									
										21
									
								
								vendor/github.com/GeertJohan/go.rice/http.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/GeertJohan/go.rice/http.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,21 +0,0 @@ | ||||
| package rice | ||||
|  | ||||
| import ( | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| // HTTPBox implements http.FileSystem which allows the use of Box with a http.FileServer. | ||||
| //   e.g.: http.Handle("/", http.FileServer(rice.MustFindBox("http-files").HTTPBox())) | ||||
| type HTTPBox struct { | ||||
| 	*Box | ||||
| } | ||||
|  | ||||
| // HTTPBox creates a new HTTPBox from an existing Box | ||||
| func (b *Box) HTTPBox() *HTTPBox { | ||||
| 	return &HTTPBox{b} | ||||
| } | ||||
|  | ||||
| // Open returns a File using the http.File interface | ||||
| func (hb *HTTPBox) Open(name string) (http.File, error) { | ||||
| 	return hb.Box.Open(name) | ||||
| } | ||||
							
								
								
									
										172
									
								
								vendor/github.com/GeertJohan/go.rice/rice/append.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										172
									
								
								vendor/github.com/GeertJohan/go.rice/rice/append.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,172 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"archive/zip" | ||||
| 	"fmt" | ||||
| 	"go/build" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/daaku/go.zipexe" | ||||
| ) | ||||
|  | ||||
| func operationAppend(pkgs []*build.Package) { | ||||
| 	if runtime.GOOS == "windows" { | ||||
| 		_, err := exec.LookPath("zip") | ||||
| 		if err != nil { | ||||
| 			fmt.Println("#### WARNING ! ####") | ||||
| 			fmt.Println("`rice append` is known not to work under windows because the `zip` command is not available. Please let me know if you got this to work (and how).") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// MARKED FOR DELETION | ||||
| 	// This is actually not required, the append command now has the option --exec required. | ||||
| 	// // check if package is a command | ||||
| 	// if !pkg.IsCommand() { | ||||
| 	// 	fmt.Println("Error: can not append to non-main package. Please follow instructions at github.com/GeertJohan/go.rice") | ||||
| 	// 	os.Exit(1) | ||||
| 	// } | ||||
|  | ||||
| 	// create tmp zipfile | ||||
| 	tmpZipfileName := filepath.Join(os.TempDir(), fmt.Sprintf("ricebox-%d-%s.zip", time.Now().Unix(), randomString(10))) | ||||
| 	verbosef("Will create tmp zipfile: %s\n", tmpZipfileName) | ||||
| 	tmpZipfile, err := os.Create(tmpZipfileName) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error creating tmp zipfile: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	defer func() { | ||||
| 		tmpZipfile.Close() | ||||
| 		os.Remove(tmpZipfileName) | ||||
| 	}() | ||||
|  | ||||
| 	// find abs path for binary file | ||||
| 	binfileName, err := filepath.Abs(flags.Append.Executable) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error finding absolute path for executable to append: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	verbosef("Will append to file: %s\n", binfileName) | ||||
|  | ||||
| 	// check that command doesn't already have zip appended | ||||
| 	if rd, _ := zipexe.Open(binfileName); rd != nil { | ||||
| 		fmt.Printf("Cannot append to already appended executable. Please remove %s and build a fresh one.\n", binfileName) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
|  | ||||
| 	// open binfile | ||||
| 	binfile, err := os.OpenFile(binfileName, os.O_WRONLY, os.ModeAppend) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error: unable to open executable file: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
|  | ||||
| 	// create zip.Writer | ||||
| 	zipWriter := zip.NewWriter(tmpZipfile) | ||||
|  | ||||
| 	for _, pkg := range pkgs { | ||||
| 		// find boxes for this command | ||||
| 		boxMap := findBoxes(pkg) | ||||
|  | ||||
| 		// notify user when no calls to rice.FindBox are made (is this an error and therefore os.Exit(1) ? | ||||
| 		if len(boxMap) == 0 { | ||||
| 			fmt.Printf("no calls to rice.FindBox() or rice.MustFindBox() found in import path `%s`\n", pkg.ImportPath) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		verbosef("\n") | ||||
|  | ||||
| 		for boxname := range boxMap { | ||||
| 			appendedBoxName := strings.Replace(boxname, `/`, `-`, -1) | ||||
|  | ||||
| 			// walk box path's and insert files | ||||
| 			boxPath := filepath.Clean(filepath.Join(pkg.Dir, boxname)) | ||||
| 			filepath.Walk(boxPath, func(path string, info os.FileInfo, err error) error { | ||||
| 				if info == nil { | ||||
| 					fmt.Printf("Error: box \"%s\" not found on disk\n", path) | ||||
| 					os.Exit(1) | ||||
| 				} | ||||
| 				// create zipFilename | ||||
| 				zipFileName := filepath.Join(appendedBoxName, strings.TrimPrefix(path, boxPath)) | ||||
| 				// write directories as empty file with comment "dir" | ||||
| 				if info.IsDir() { | ||||
| 					_, err := zipWriter.CreateHeader(&zip.FileHeader{ | ||||
| 						Name:    zipFileName, | ||||
| 						Comment: "dir", | ||||
| 					}) | ||||
| 					if err != nil { | ||||
| 						fmt.Printf("Error creating dir in tmp zip: %s\n", err) | ||||
| 						os.Exit(1) | ||||
| 					} | ||||
| 					return nil | ||||
| 				} | ||||
|  | ||||
| 				// create zipFileWriter | ||||
| 				zipFileHeader, err := zip.FileInfoHeader(info) | ||||
| 				if err != nil { | ||||
| 					fmt.Printf("Error creating zip FileHeader: %v\n", err) | ||||
| 					os.Exit(1) | ||||
| 				} | ||||
| 				zipFileHeader.Name = zipFileName | ||||
| 				zipFileWriter, err := zipWriter.CreateHeader(zipFileHeader) | ||||
| 				if err != nil { | ||||
| 					fmt.Printf("Error creating file in tmp zip: %s\n", err) | ||||
| 					os.Exit(1) | ||||
| 				} | ||||
| 				srcFile, err := os.Open(path) | ||||
| 				if err != nil { | ||||
| 					fmt.Printf("Error opening file to append: %s\n", err) | ||||
| 					os.Exit(1) | ||||
| 				} | ||||
| 				_, err = io.Copy(zipFileWriter, srcFile) | ||||
| 				if err != nil { | ||||
| 					fmt.Printf("Error copying file contents to zip: %s\n", err) | ||||
| 					os.Exit(1) | ||||
| 				} | ||||
| 				srcFile.Close() | ||||
|  | ||||
| 				return nil | ||||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	err = zipWriter.Close() | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error closing tmp zipfile: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
|  | ||||
| 	err = tmpZipfile.Sync() | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error syncing tmp zipfile: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	_, err = tmpZipfile.Seek(0, 0) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error seeking tmp zipfile: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	_, err = binfile.Seek(0, 2) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error seeking bin file: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
|  | ||||
| 	_, err = io.Copy(binfile, tmpZipfile) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error appending zipfile to executable: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
|  | ||||
| 	zipA := exec.Command("zip", "-A", binfileName) | ||||
| 	err = zipA.Run() | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error setting zip offset: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										33
									
								
								vendor/github.com/GeertJohan/go.rice/rice/clean.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								vendor/github.com/GeertJohan/go.rice/rice/clean.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,33 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"go/build" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| func operationClean(pkg *build.Package) { | ||||
| 	filepath.Walk(pkg.Dir, func(filename string, info os.FileInfo, err error) error { | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("error walking pkg dir to clean files: %v\n", err) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		if info.IsDir() { | ||||
| 			return nil | ||||
| 		} | ||||
| 		verbosef("checking file '%s'\n", filename) | ||||
| 		if filepath.Base(filename) == "rice-box.go" || | ||||
| 			strings.HasSuffix(filename, ".rice-box.go") || | ||||
| 			strings.HasSuffix(filename, ".rice-box.syso") { | ||||
| 			err := os.Remove(filename) | ||||
| 			if err != nil { | ||||
| 				fmt.Printf("error removing file (%s): %s\n", filename, err) | ||||
| 				os.Exit(-1) | ||||
| 			} | ||||
| 			verbosef("removed file '%s'\n", filename) | ||||
| 		} | ||||
| 		return nil | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										158
									
								
								vendor/github.com/GeertJohan/go.rice/rice/embed-go.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										158
									
								
								vendor/github.com/GeertJohan/go.rice/rice/embed-go.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,158 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"go/build" | ||||
| 	"go/format" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| const boxFilename = "rice-box.go" | ||||
|  | ||||
| func operationEmbedGo(pkg *build.Package) { | ||||
|  | ||||
| 	boxMap := findBoxes(pkg) | ||||
|  | ||||
| 	// notify user when no calls to rice.FindBox are made (is this an error and therefore os.Exit(1) ? | ||||
| 	if len(boxMap) == 0 { | ||||
| 		fmt.Println("no calls to rice.FindBox() found") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	verbosef("\n") | ||||
| 	var boxes []*boxDataType | ||||
|  | ||||
| 	for boxname := range boxMap { | ||||
| 		// find path and filename for this box | ||||
| 		boxPath := filepath.Join(pkg.Dir, boxname) | ||||
|  | ||||
| 		// Check to see if the path for the box is a symbolic link.  If so, simply | ||||
| 		// box what the symbolic link points to.  Note: the filepath.Walk function | ||||
| 		// will NOT follow any nested symbolic links.  This only handles the case | ||||
| 		// where the root of the box is a symbolic link. | ||||
| 		symPath, serr := os.Readlink(boxPath) | ||||
| 		if serr == nil { | ||||
| 			boxPath = symPath | ||||
| 		} | ||||
|  | ||||
| 		// verbose info | ||||
| 		verbosef("embedding box '%s' to '%s'\n", boxname, boxFilename) | ||||
|  | ||||
| 		// read box metadata | ||||
| 		boxInfo, ierr := os.Stat(boxPath) | ||||
| 		if ierr != nil { | ||||
| 			fmt.Printf("Error: unable to access box at %s\n", boxPath) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
|  | ||||
| 		// create box datastructure (used by template) | ||||
| 		box := &boxDataType{ | ||||
| 			BoxName: boxname, | ||||
| 			UnixNow: boxInfo.ModTime().Unix(), | ||||
| 			Files:   make([]*fileDataType, 0), | ||||
| 			Dirs:    make(map[string]*dirDataType), | ||||
| 		} | ||||
|  | ||||
| 		if !boxInfo.IsDir() { | ||||
| 			fmt.Printf("Error: Box %s must point to a directory but points to %s instead\n", | ||||
| 				boxname, boxPath) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
|  | ||||
| 		// fill box datastructure with file data | ||||
| 		filepath.Walk(boxPath, func(path string, info os.FileInfo, err error) error { | ||||
| 			if err != nil { | ||||
| 				fmt.Printf("error walking box: %s\n", err) | ||||
| 				os.Exit(1) | ||||
| 			} | ||||
|  | ||||
| 			filename := strings.TrimPrefix(path, boxPath) | ||||
| 			filename = strings.Replace(filename, "\\", "/", -1) | ||||
| 			filename = strings.TrimPrefix(filename, "/") | ||||
| 			if info.IsDir() { | ||||
| 				dirData := &dirDataType{ | ||||
| 					Identifier: "dir" + nextIdentifier(), | ||||
| 					FileName:   filename, | ||||
| 					ModTime:    info.ModTime().Unix(), | ||||
| 					ChildFiles: make([]*fileDataType, 0), | ||||
| 					ChildDirs:  make([]*dirDataType, 0), | ||||
| 				} | ||||
| 				verbosef("\tincludes dir: '%s'\n", dirData.FileName) | ||||
| 				box.Dirs[dirData.FileName] = dirData | ||||
|  | ||||
| 				// add tree entry (skip for root, it'll create a recursion) | ||||
| 				if dirData.FileName != "" { | ||||
| 					pathParts := strings.Split(dirData.FileName, "/") | ||||
| 					parentDir := box.Dirs[strings.Join(pathParts[:len(pathParts)-1], "/")] | ||||
| 					parentDir.ChildDirs = append(parentDir.ChildDirs, dirData) | ||||
| 				} | ||||
| 			} else { | ||||
| 				fileData := &fileDataType{ | ||||
| 					Identifier: "file" + nextIdentifier(), | ||||
| 					FileName:   filename, | ||||
| 					ModTime:    info.ModTime().Unix(), | ||||
| 				} | ||||
| 				verbosef("\tincludes file: '%s'\n", fileData.FileName) | ||||
| 				fileData.Content, err = ioutil.ReadFile(path) | ||||
| 				if err != nil { | ||||
| 					fmt.Printf("error reading file content while walking box: %s\n", err) | ||||
| 					os.Exit(1) | ||||
| 				} | ||||
| 				box.Files = append(box.Files, fileData) | ||||
|  | ||||
| 				// add tree entry | ||||
| 				pathParts := strings.Split(fileData.FileName, "/") | ||||
| 				parentDir := box.Dirs[strings.Join(pathParts[:len(pathParts)-1], "/")] | ||||
| 				if parentDir == nil { | ||||
| 					fmt.Printf("Error: parent of %s is not within the box\n", path) | ||||
| 					os.Exit(1) | ||||
| 				} | ||||
| 				parentDir.ChildFiles = append(parentDir.ChildFiles, fileData) | ||||
| 			} | ||||
| 			return nil | ||||
| 		}) | ||||
| 		boxes = append(boxes, box) | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	embedSourceUnformated := bytes.NewBuffer(make([]byte, 0)) | ||||
|  | ||||
| 	// execute template to buffer | ||||
| 	err := tmplEmbeddedBox.Execute( | ||||
| 		embedSourceUnformated, | ||||
| 		embedFileDataType{pkg.Name, boxes}, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		log.Printf("error writing embedded box to file (template execute): %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
|  | ||||
| 	// format the source code | ||||
| 	embedSource, err := format.Source(embedSourceUnformated.Bytes()) | ||||
| 	if err != nil { | ||||
| 		log.Printf("error formatting embedSource: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
|  | ||||
| 	// create go file for box | ||||
| 	boxFile, err := os.Create(filepath.Join(pkg.Dir, boxFilename)) | ||||
| 	if err != nil { | ||||
| 		log.Printf("error creating embedded box file: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	defer boxFile.Close() | ||||
|  | ||||
| 	// write source to file | ||||
| 	_, err = io.Copy(boxFile, bytes.NewBuffer(embedSource)) | ||||
| 	if err != nil { | ||||
| 		log.Printf("error writing embedSource to file: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
|  | ||||
| } | ||||
							
								
								
									
										204
									
								
								vendor/github.com/GeertJohan/go.rice/rice/embed-syso.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										204
									
								
								vendor/github.com/GeertJohan/go.rice/rice/embed-syso.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,204 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/gob" | ||||
| 	"fmt" | ||||
| 	"go/build" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"text/template" | ||||
|  | ||||
| 	"github.com/GeertJohan/go.rice/embedded" | ||||
| 	"github.com/akavel/rsrc/coff" | ||||
| ) | ||||
|  | ||||
| type sizedReader struct { | ||||
| 	*bytes.Reader | ||||
| } | ||||
|  | ||||
| func (s sizedReader) Size() int64 { | ||||
| 	return int64(s.Len()) | ||||
| } | ||||
|  | ||||
| var tmplEmbeddedSysoHelper *template.Template | ||||
|  | ||||
| func init() { | ||||
| 	var err error | ||||
| 	tmplEmbeddedSysoHelper, err = template.New("embeddedSysoHelper").Parse(`package {{.Package}} | ||||
| // ############# GENERATED CODE ##################### | ||||
| // ## This file was generated by the rice tool. | ||||
| // ## Do not edit unless you know what you're doing. | ||||
| // ################################################## | ||||
|  | ||||
| // extern char _bricebox_{{.Symname}}[], _ericebox_{{.Symname}}; | ||||
| // int get_{{.Symname}}_length() { | ||||
| // 	return &_ericebox_{{.Symname}} - _bricebox_{{.Symname}}; | ||||
| // } | ||||
| import "C" | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/gob" | ||||
| 	"github.com/GeertJohan/go.rice/embedded" | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	ptr := unsafe.Pointer(&C._bricebox_{{.Symname}}) | ||||
| 	bts := C.GoBytes(ptr, C.get_{{.Symname}}_length()) | ||||
| 	embeddedBox := &embedded.EmbeddedBox{} | ||||
| 	err := gob.NewDecoder(bytes.NewReader(bts)).Decode(embeddedBox) | ||||
| 	if err != nil { | ||||
| 		panic("error decoding embedded box: "+err.Error()) | ||||
| 	} | ||||
| 	embeddedBox.Link() | ||||
| 	embedded.RegisterEmbeddedBox(embeddedBox.Name, embeddedBox) | ||||
| }`) | ||||
| 	if err != nil { | ||||
| 		panic("could not parse template embeddedSysoHelper: " + err.Error()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type embeddedSysoHelperData struct { | ||||
| 	Package string | ||||
| 	Symname string | ||||
| } | ||||
|  | ||||
| func operationEmbedSyso(pkg *build.Package) { | ||||
|  | ||||
| 	regexpSynameReplacer := regexp.MustCompile(`[^a-z0-9_]`) | ||||
|  | ||||
| 	boxMap := findBoxes(pkg) | ||||
|  | ||||
| 	// notify user when no calls to rice.FindBox are made (is this an error and therefore os.Exit(1) ? | ||||
| 	if len(boxMap) == 0 { | ||||
| 		fmt.Println("no calls to rice.FindBox() found") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	verbosef("\n") | ||||
|  | ||||
| 	for boxname := range boxMap { | ||||
| 		// find path and filename for this box | ||||
| 		boxPath := filepath.Join(pkg.Dir, boxname) | ||||
| 		boxFilename := strings.Replace(boxname, "/", "-", -1) | ||||
| 		boxFilename = strings.Replace(boxFilename, "..", "back", -1) | ||||
| 		boxFilename = strings.Replace(boxFilename, ".", "-", -1) | ||||
|  | ||||
| 		// verbose info | ||||
| 		verbosef("embedding box '%s'\n", boxname) | ||||
| 		verbosef("\tto file %s\n", boxFilename) | ||||
|  | ||||
| 		// read box metadata | ||||
| 		boxInfo, ierr := os.Stat(boxPath) | ||||
| 		if ierr != nil { | ||||
| 			fmt.Printf("Error: unable to access box at %s\n", boxPath) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
|  | ||||
| 		// create box datastructure (used by template) | ||||
| 		box := &embedded.EmbeddedBox{ | ||||
| 			Name:      boxname, | ||||
| 			Time:      boxInfo.ModTime(), | ||||
| 			EmbedType: embedded.EmbedTypeSyso, | ||||
| 			Files:     make(map[string]*embedded.EmbeddedFile), | ||||
| 			Dirs:      make(map[string]*embedded.EmbeddedDir), | ||||
| 		} | ||||
|  | ||||
| 		// fill box datastructure with file data | ||||
| 		filepath.Walk(boxPath, func(path string, info os.FileInfo, err error) error { | ||||
| 			if err != nil { | ||||
| 				fmt.Printf("error walking box: %s\n", err) | ||||
| 				os.Exit(1) | ||||
| 			} | ||||
|  | ||||
| 			filename := strings.TrimPrefix(path, boxPath) | ||||
| 			filename = strings.Replace(filename, "\\", "/", -1) | ||||
| 			filename = strings.TrimPrefix(filename, "/") | ||||
| 			if info.IsDir() { | ||||
| 				embeddedDir := &embedded.EmbeddedDir{ | ||||
| 					Filename:   filename, | ||||
| 					DirModTime: info.ModTime(), | ||||
| 				} | ||||
| 				verbosef("\tincludes dir: '%s'\n", embeddedDir.Filename) | ||||
| 				box.Dirs[embeddedDir.Filename] = embeddedDir | ||||
|  | ||||
| 				// add tree entry (skip for root, it'll create a recursion) | ||||
| 				if embeddedDir.Filename != "" { | ||||
| 					pathParts := strings.Split(embeddedDir.Filename, "/") | ||||
| 					parentDir := box.Dirs[strings.Join(pathParts[:len(pathParts)-1], "/")] | ||||
| 					parentDir.ChildDirs = append(parentDir.ChildDirs, embeddedDir) | ||||
| 				} | ||||
| 			} else { | ||||
| 				embeddedFile := &embedded.EmbeddedFile{ | ||||
| 					Filename:    filename, | ||||
| 					FileModTime: info.ModTime(), | ||||
| 					Content:     "", | ||||
| 				} | ||||
| 				verbosef("\tincludes file: '%s'\n", embeddedFile.Filename) | ||||
| 				contentBytes, err := ioutil.ReadFile(path) | ||||
| 				if err != nil { | ||||
| 					fmt.Printf("error reading file content while walking box: %s\n", err) | ||||
| 					os.Exit(1) | ||||
| 				} | ||||
| 				embeddedFile.Content = string(contentBytes) | ||||
| 				box.Files[embeddedFile.Filename] = embeddedFile | ||||
| 			} | ||||
| 			return nil | ||||
| 		}) | ||||
|  | ||||
| 		// encode embedded box to gob file | ||||
| 		boxGobBuf := &bytes.Buffer{} | ||||
| 		err := gob.NewEncoder(boxGobBuf).Encode(box) | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("error encoding box to gob: %v\n", err) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
|  | ||||
| 		verbosef("gob-encoded embeddedBox is %d bytes large\n", boxGobBuf.Len()) | ||||
|  | ||||
| 		// write coff | ||||
| 		symname := regexpSynameReplacer.ReplaceAllString(boxname, "_") | ||||
| 		createCoffSyso(boxname, symname, "386", boxGobBuf.Bytes()) | ||||
| 		createCoffSyso(boxname, symname, "amd64", boxGobBuf.Bytes()) | ||||
|  | ||||
| 		// write go | ||||
| 		sysoHelperData := embeddedSysoHelperData{ | ||||
| 			Package: pkg.Name, | ||||
| 			Symname: symname, | ||||
| 		} | ||||
| 		fileSysoHelper, err := os.Create(boxFilename + ".rice-box.go") | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("error creating syso helper: %v\n", err) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		err = tmplEmbeddedSysoHelper.Execute(fileSysoHelper, sysoHelperData) | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("error executing tmplEmbeddedSysoHelper: %v\n", err) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func createCoffSyso(boxFilename string, symname string, arch string, data []byte) { | ||||
| 	boxCoff := coff.NewRDATA() | ||||
| 	switch arch { | ||||
| 	case "386": | ||||
| 	case "amd64": | ||||
| 		boxCoff.FileHeader.Machine = 0x8664 | ||||
| 	default: | ||||
| 		panic("invalid arch") | ||||
| 	} | ||||
| 	boxCoff.AddData("_bricebox_"+symname, sizedReader{bytes.NewReader(data)}) | ||||
| 	boxCoff.AddData("_ericebox_"+symname, io.NewSectionReader(strings.NewReader("\000\000"), 0, 2)) // TODO: why? copied from rsrc, which copied it from as-generated | ||||
| 	boxCoff.Freeze() | ||||
| 	err := writeCoff(boxCoff, boxFilename+"_"+arch+".rice-box.syso") | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("error writing %s coff/.syso: %v\n", arch, err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										150
									
								
								vendor/github.com/GeertJohan/go.rice/rice/find.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										150
									
								
								vendor/github.com/GeertJohan/go.rice/rice/find.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,150 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"go/build" | ||||
| 	"go/parser" | ||||
| 	"go/token" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| func badArgument(fileset *token.FileSet, p token.Pos) { | ||||
| 	pos := fileset.Position(p) | ||||
| 	filename := pos.Filename | ||||
| 	base, err := os.Getwd() | ||||
| 	if err == nil { | ||||
| 		rpath, perr := filepath.Rel(base, pos.Filename) | ||||
| 		if perr == nil { | ||||
| 			filename = rpath | ||||
| 		} | ||||
| 	} | ||||
| 	msg := fmt.Sprintf("%s:%d: Error: found call to rice.FindBox, "+ | ||||
| 		"but argument must be a string literal.\n", filename, pos.Line) | ||||
| 	fmt.Println(msg) | ||||
| 	os.Exit(1) | ||||
| } | ||||
|  | ||||
| func findBoxes(pkg *build.Package) map[string]bool { | ||||
| 	// create map of boxes to embed | ||||
| 	var boxMap = make(map[string]bool) | ||||
|  | ||||
| 	// create one list of files for this package | ||||
| 	filenames := make([]string, 0, len(pkg.GoFiles)+len(pkg.CgoFiles)) | ||||
| 	filenames = append(filenames, pkg.GoFiles...) | ||||
| 	filenames = append(filenames, pkg.CgoFiles...) | ||||
|  | ||||
| 	// loop over files, search for rice.FindBox(..) calls | ||||
| 	for _, filename := range filenames { | ||||
| 		// find full filepath | ||||
| 		fullpath := filepath.Join(pkg.Dir, filename) | ||||
| 		if strings.HasSuffix(filename, "rice-box.go") { | ||||
| 			// Ignore *.rice-box.go files | ||||
| 			verbosef("skipping file %q\n", fullpath) | ||||
| 			continue | ||||
| 		} | ||||
| 		verbosef("scanning file %q\n", fullpath) | ||||
|  | ||||
| 		fset := token.NewFileSet() | ||||
| 		f, err := parser.ParseFile(fset, fullpath, nil, 0) | ||||
| 		if err != nil { | ||||
| 			fmt.Println(err) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
|  | ||||
| 		var riceIsImported bool | ||||
| 		ricePkgName := "rice" | ||||
| 		for _, imp := range f.Imports { | ||||
| 			if strings.HasSuffix(imp.Path.Value, "go.rice\"") { | ||||
| 				if imp.Name != nil { | ||||
| 					ricePkgName = imp.Name.Name | ||||
| 				} | ||||
| 				riceIsImported = true | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		if !riceIsImported { | ||||
| 			// Rice wasn't imported, so we won't find a box. | ||||
| 			continue | ||||
| 		} | ||||
| 		if ricePkgName == "_" { | ||||
| 			// Rice pkg is unnamed, so we won't find a box. | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// Inspect AST, looking for calls to (Must)?FindBox. | ||||
| 		// First parameter of the func must be a basic literal. | ||||
| 		// Identifiers won't be resolved. | ||||
| 		var nextIdentIsBoxFunc bool | ||||
| 		var nextBasicLitParamIsBoxName bool | ||||
| 		var boxCall token.Pos | ||||
| 		var variableToRemember string | ||||
| 		var validVariablesForBoxes map[string]bool = make(map[string]bool) | ||||
|  | ||||
| 		ast.Inspect(f, func(node ast.Node) bool { | ||||
| 			if node == nil { | ||||
| 				return false | ||||
| 			} | ||||
| 			switch x := node.(type) { | ||||
| 			// this case fixes the var := func() style assignments, not assignments to vars declared separately from the assignment. | ||||
| 			case *ast.AssignStmt: | ||||
| 				var assign = node.(*ast.AssignStmt) | ||||
| 				name, found := assign.Lhs[0].(*ast.Ident) | ||||
| 				if found { | ||||
| 					variableToRemember = name.Name | ||||
| 					composite, first := assign.Rhs[0].(*ast.CompositeLit) | ||||
| 					if first { | ||||
| 						riceSelector, second := composite.Type.(*ast.SelectorExpr) | ||||
|  | ||||
| 						if second { | ||||
| 							callCorrect := riceSelector.Sel.Name == "Config" | ||||
| 							packageName, third := riceSelector.X.(*ast.Ident) | ||||
|  | ||||
| 							if third && callCorrect && packageName.Name == ricePkgName { | ||||
| 								validVariablesForBoxes[name.Name] = true | ||||
| 								verbosef("\tfound variable, saving to scan for boxes: %q\n", name.Name) | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			case *ast.Ident: | ||||
| 				if nextIdentIsBoxFunc || ricePkgName == "." { | ||||
| 					nextIdentIsBoxFunc = false | ||||
| 					if x.Name == "FindBox" || x.Name == "MustFindBox" { | ||||
| 						nextBasicLitParamIsBoxName = true | ||||
| 						boxCall = x.Pos() | ||||
| 					} | ||||
| 				} else { | ||||
| 					if x.Name == ricePkgName || validVariablesForBoxes[x.Name] { | ||||
| 						nextIdentIsBoxFunc = true | ||||
| 					} | ||||
| 				} | ||||
| 			case *ast.BasicLit: | ||||
| 				if nextBasicLitParamIsBoxName { | ||||
| 					if x.Kind == token.STRING { | ||||
| 						nextBasicLitParamIsBoxName = false | ||||
| 						// trim "" or `` | ||||
| 						name := x.Value[1 : len(x.Value)-1] | ||||
| 						boxMap[name] = true | ||||
| 						verbosef("\tfound box %q\n", name) | ||||
| 					} else { | ||||
| 						badArgument(fset, boxCall) | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 			default: | ||||
| 				if nextIdentIsBoxFunc { | ||||
| 					nextIdentIsBoxFunc = false | ||||
| 				} | ||||
| 				if nextBasicLitParamIsBoxName { | ||||
| 					badArgument(fset, boxCall) | ||||
| 				} | ||||
| 			} | ||||
| 			return true | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	return boxMap | ||||
| } | ||||
							
								
								
									
										80
									
								
								vendor/github.com/GeertJohan/go.rice/rice/flags.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										80
									
								
								vendor/github.com/GeertJohan/go.rice/rice/flags.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,80 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"go/build" | ||||
| 	"os" | ||||
|  | ||||
| 	goflags "github.com/jessevdk/go-flags" // rename import to `goflags` (file scope) so we can use `var flags` (package scope) | ||||
| ) | ||||
|  | ||||
| // flags | ||||
| var flags struct { | ||||
| 	Verbose     bool     `long:"verbose" short:"v" description:"Show verbose debug information"` | ||||
| 	ImportPaths []string `long:"import-path" short:"i" description:"Import path(s) to use. Using PWD when left empty. Specify multiple times for more import paths to append"` | ||||
|  | ||||
| 	Append struct { | ||||
| 		Executable string `long:"exec" description:"Executable to append" required:"true"` | ||||
| 	} `command:"append"` | ||||
|  | ||||
| 	EmbedGo   struct{} `command:"embed-go" alias:"embed"` | ||||
| 	EmbedSyso struct{} `command:"embed-syso"` | ||||
| 	Clean     struct{} `command:"clean"` | ||||
| } | ||||
|  | ||||
| // flags parser | ||||
| var flagsParser *goflags.Parser | ||||
|  | ||||
| // initFlags parses the given flags. | ||||
| // when the user asks for help (-h or --help): the application exists with status 0 | ||||
| // when unexpected flags is given: the application exits with status 1 | ||||
| func parseArguments() { | ||||
| 	// create flags parser in global var, for flagsParser.Active.Name (operation) | ||||
| 	flagsParser = goflags.NewParser(&flags, goflags.Default) | ||||
|  | ||||
| 	// parse flags | ||||
| 	args, err := flagsParser.Parse() | ||||
| 	if err != nil { | ||||
| 		// assert the err to be a flags.Error | ||||
| 		flagError := err.(*goflags.Error) | ||||
| 		if flagError.Type == goflags.ErrHelp { | ||||
| 			// user asked for help on flags. | ||||
| 			// program can exit successfully | ||||
| 			os.Exit(0) | ||||
| 		} | ||||
| 		if flagError.Type == goflags.ErrUnknownFlag { | ||||
| 			fmt.Println("Use --help to view available options.") | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		if flagError.Type == goflags.ErrRequired { | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		fmt.Printf("Error parsing flags: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
|  | ||||
| 	// error on left-over arguments | ||||
| 	if len(args) > 0 { | ||||
| 		fmt.Printf("Unexpected arguments: %s\nUse --help to view available options.", args) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
|  | ||||
| 	// default ImportPath to pwd when not set | ||||
| 	if len(flags.ImportPaths) == 0 { | ||||
| 		pwd, err := os.Getwd() | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("error getting pwd: %s\n", err) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		verbosef("using pwd as import path\n") | ||||
| 		// find non-absolute path for this pwd | ||||
| 		pkg, err := build.ImportDir(pwd, build.FindOnly) | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("error using current directory as import path: %s\n", err) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		flags.ImportPaths = append(flags.ImportPaths, pkg.ImportPath) | ||||
| 		verbosef("using import paths: %s\n", flags.ImportPaths) | ||||
| 		return | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										14
									
								
								vendor/github.com/GeertJohan/go.rice/rice/identifier.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/GeertJohan/go.rice/rice/identifier.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,14 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/GeertJohan/go.incremental" | ||||
| ) | ||||
|  | ||||
| var identifierCount incremental.Uint64 | ||||
|  | ||||
| func nextIdentifier() string { | ||||
| 	num := identifierCount.Next() | ||||
| 	return strconv.FormatUint(num, 36) // 0123456789abcdefghijklmnopqrstuvwxyz | ||||
| } | ||||
							
								
								
									
										68
									
								
								vendor/github.com/GeertJohan/go.rice/rice/main.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										68
									
								
								vendor/github.com/GeertJohan/go.rice/rice/main.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,68 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"go/build" | ||||
| 	"log" | ||||
| 	"os" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	// parser arguments | ||||
| 	parseArguments() | ||||
|  | ||||
| 	// find package for path | ||||
| 	var pkgs []*build.Package | ||||
| 	for _, importPath := range flags.ImportPaths { | ||||
| 		pkg := pkgForPath(importPath) | ||||
| 		pkgs = append(pkgs, pkg) | ||||
| 	} | ||||
|  | ||||
| 	// switch on the operation to perform | ||||
| 	switch flagsParser.Active.Name { | ||||
| 	case "embed", "embed-go": | ||||
| 		for _, pkg := range pkgs { | ||||
| 			operationEmbedGo(pkg) | ||||
| 		} | ||||
| 	case "embed-syso": | ||||
| 		log.Println("WARNING: embedding .syso is experimental..") | ||||
| 		for _, pkg := range pkgs { | ||||
| 			operationEmbedSyso(pkg) | ||||
| 		} | ||||
| 	case "append": | ||||
| 		operationAppend(pkgs) | ||||
| 	case "clean": | ||||
| 		for _, pkg := range pkgs { | ||||
| 			operationClean(pkg) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// all done | ||||
| 	verbosef("\n") | ||||
| 	verbosef("rice finished successfully\n") | ||||
| } | ||||
|  | ||||
| // helper function to get *build.Package for given path | ||||
| func pkgForPath(path string) *build.Package { | ||||
| 	// get pwd for relative imports | ||||
| 	pwd, err := os.Getwd() | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("error getting pwd (required for relative imports): %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
|  | ||||
| 	// read full package information | ||||
| 	pkg, err := build.Import(path, pwd, 0) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("error reading package: %s\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
|  | ||||
| 	return pkg | ||||
| } | ||||
|  | ||||
| func verbosef(format string, stuff ...interface{}) { | ||||
| 	if flags.Verbose { | ||||
| 		log.Printf(format, stuff...) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										98
									
								
								vendor/github.com/GeertJohan/go.rice/rice/templates.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										98
									
								
								vendor/github.com/GeertJohan/go.rice/rice/templates.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,98 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"text/template" | ||||
| ) | ||||
|  | ||||
| var tmplEmbeddedBox *template.Template | ||||
|  | ||||
| func init() { | ||||
| 	var err error | ||||
|  | ||||
| 	// parse embedded box template | ||||
| 	tmplEmbeddedBox, err = template.New("embeddedBox").Parse(`package {{.Package}} | ||||
|  | ||||
| import ( | ||||
| 	"github.com/GeertJohan/go.rice/embedded" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| {{range .Boxes}} | ||||
| func init() { | ||||
|  | ||||
| 	// define files | ||||
| 	{{range .Files}}{{.Identifier}} := &embedded.EmbeddedFile{ | ||||
| 		Filename:    ` + "`" + `{{.FileName}}` + "`" + `, | ||||
| 		FileModTime: time.Unix({{.ModTime}}, 0), | ||||
| 		Content:     string({{.Content | printf "%q"}}),  | ||||
| 	} | ||||
| 	{{end}} | ||||
|  | ||||
| 	// define dirs | ||||
| 	{{range .Dirs}}{{.Identifier}} := &embedded.EmbeddedDir{ | ||||
| 		Filename:    ` + "`" + `{{.FileName}}` + "`" + `, | ||||
| 		DirModTime: time.Unix({{.ModTime}}, 0), | ||||
| 		ChildFiles:  []*embedded.EmbeddedFile{ | ||||
| 			{{range .ChildFiles}}{{.Identifier}}, // {{.FileName}} | ||||
| 			{{end}} | ||||
| 		}, | ||||
| 	} | ||||
| 	{{end}} | ||||
|  | ||||
| 	// link ChildDirs | ||||
| 	{{range .Dirs}}{{.Identifier}}.ChildDirs = []*embedded.EmbeddedDir{ | ||||
| 		{{range .ChildDirs}}{{.Identifier}}, // {{.FileName}} | ||||
| 		{{end}} | ||||
| 	} | ||||
| 	{{end}} | ||||
|  | ||||
| 	// register embeddedBox | ||||
| 	embedded.RegisterEmbeddedBox(` + "`" + `{{.BoxName}}` + "`" + `, &embedded.EmbeddedBox{ | ||||
| 		Name: ` + "`" + `{{.BoxName}}` + "`" + `, | ||||
| 		Time: time.Unix({{.UnixNow}}, 0), | ||||
| 		Dirs: map[string]*embedded.EmbeddedDir{ | ||||
| 			{{range .Dirs}}"{{.FileName}}": {{.Identifier}}, | ||||
| 			{{end}} | ||||
| 		}, | ||||
| 		Files: map[string]*embedded.EmbeddedFile{ | ||||
| 			{{range .Files}}"{{.FileName}}": {{.Identifier}}, | ||||
| 			{{end}} | ||||
| 		}, | ||||
| 	}) | ||||
| } | ||||
| {{end}}`) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("error parsing embedded box template: %s\n", err) | ||||
| 		os.Exit(-1) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type embedFileDataType struct { | ||||
| 	Package string | ||||
| 	Boxes   []*boxDataType | ||||
| } | ||||
|  | ||||
| type boxDataType struct { | ||||
| 	BoxName string | ||||
| 	UnixNow int64 | ||||
| 	Files   []*fileDataType | ||||
| 	Dirs    map[string]*dirDataType | ||||
| } | ||||
|  | ||||
| type fileDataType struct { | ||||
| 	Identifier string | ||||
| 	FileName   string | ||||
| 	Content    []byte | ||||
| 	ModTime    int64 | ||||
| } | ||||
|  | ||||
| type dirDataType struct { | ||||
| 	Identifier string | ||||
| 	FileName   string | ||||
| 	Content    []byte | ||||
| 	ModTime    int64 | ||||
| 	ChildDirs  []*dirDataType | ||||
| 	ChildFiles []*fileDataType | ||||
| } | ||||
							
								
								
									
										22
									
								
								vendor/github.com/GeertJohan/go.rice/rice/util.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/GeertJohan/go.rice/rice/util.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,22 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"math/rand" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // randomString generates a pseudo-random alpha-numeric string with given length. | ||||
| func randomString(length int) string { | ||||
| 	rand.Seed(time.Now().UnixNano()) | ||||
| 	k := make([]rune, length) | ||||
| 	for i := 0; i < length; i++ { | ||||
| 		c := rand.Intn(35) | ||||
| 		if c < 10 { | ||||
| 			c += 48 // numbers (0-9) (0+48 == 48 == '0', 9+48 == 57 == '9') | ||||
| 		} else { | ||||
| 			c += 87 // lower case alphabets (a-z) (10+87 == 97 == 'a', 35+87 == 122 = 'z') | ||||
| 		} | ||||
| 		k[i] = rune(c) | ||||
| 	} | ||||
| 	return string(k) | ||||
| } | ||||
							
								
								
									
										42
									
								
								vendor/github.com/GeertJohan/go.rice/rice/writecoff.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/GeertJohan/go.rice/rice/writecoff.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,42 +0,0 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
|  | ||||
| 	"github.com/akavel/rsrc/binutil" | ||||
| 	"github.com/akavel/rsrc/coff" | ||||
| ) | ||||
|  | ||||
| // copied from github.com/akavel/rsrc | ||||
| // LICENSE: MIT | ||||
| // Copyright 2013-2014 The rsrc Authors. (https://github.com/akavel/rsrc/blob/master/AUTHORS) | ||||
| func writeCoff(coff *coff.Coff, fnameout string) error { | ||||
| 	out, err := os.Create(fnameout) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer out.Close() | ||||
| 	w := binutil.Writer{W: out} | ||||
|  | ||||
| 	// write the resulting file to disk | ||||
| 	binutil.Walk(coff, func(v reflect.Value, path string) error { | ||||
| 		if binutil.Plain(v.Kind()) { | ||||
| 			w.WriteLE(v.Interface()) | ||||
| 			return nil | ||||
| 		} | ||||
| 		vv, ok := v.Interface().(binutil.SizedReader) | ||||
| 		if ok { | ||||
| 			w.WriteFromSized(vv) | ||||
| 			return binutil.WALK_SKIP | ||||
| 		} | ||||
| 		return nil | ||||
| 	}) | ||||
|  | ||||
| 	if w.Err != nil { | ||||
| 		return fmt.Errorf("Error writing output file: %s", w.Err) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										19
									
								
								vendor/github.com/GeertJohan/go.rice/sort.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/GeertJohan/go.rice/sort.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,19 +0,0 @@ | ||||
| package rice | ||||
|  | ||||
| import "os" | ||||
|  | ||||
| // SortByName allows an array of os.FileInfo objects | ||||
| // to be easily sorted by filename using sort.Sort(SortByName(array)) | ||||
| type SortByName []os.FileInfo | ||||
|  | ||||
| func (f SortByName) Len() int           { return len(f) } | ||||
| func (f SortByName) Less(i, j int) bool { return f[i].Name() < f[j].Name() } | ||||
| func (f SortByName) Swap(i, j int)      { f[i], f[j] = f[j], f[i] } | ||||
|  | ||||
| // SortByModified allows an array of os.FileInfo objects | ||||
| // to be easily sorted by modified date using sort.Sort(SortByModified(array)) | ||||
| type SortByModified []os.FileInfo | ||||
|  | ||||
| func (f SortByModified) Len() int           { return len(f) } | ||||
| func (f SortByModified) Less(i, j int) bool { return f[i].ModTime().Unix() > f[j].ModTime().Unix() } | ||||
| func (f SortByModified) Swap(i, j int)      { f[i], f[j] = f[j], f[i] } | ||||
							
								
								
									
										252
									
								
								vendor/github.com/GeertJohan/go.rice/virtual.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										252
									
								
								vendor/github.com/GeertJohan/go.rice/virtual.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,252 +0,0 @@ | ||||
| package rice | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"sort" | ||||
|  | ||||
| 	"github.com/GeertJohan/go.rice/embedded" | ||||
| ) | ||||
|  | ||||
| //++ TODO: IDEA: merge virtualFile and virtualDir, this decreases work done by rice.File | ||||
|  | ||||
| // Error indicating some function is not implemented yet (but available to satisfy an interface) | ||||
| var ErrNotImplemented = errors.New("not implemented yet") | ||||
|  | ||||
| // virtualFile is a 'stateful' virtual file. | ||||
| // virtualFile wraps an *EmbeddedFile for a call to Box.Open() and virtualizes 'read cursor' (offset) and 'closing'. | ||||
| // virtualFile is only internally visible and should be exposed through rice.File | ||||
| type virtualFile struct { | ||||
| 	*embedded.EmbeddedFile       // the actual embedded file, embedded to obtain methods | ||||
| 	offset                 int64 // read position on the virtual file | ||||
| 	closed                 bool  // closed when true | ||||
| } | ||||
|  | ||||
| // create a new virtualFile for given EmbeddedFile | ||||
| func newVirtualFile(ef *embedded.EmbeddedFile) *virtualFile { | ||||
| 	vf := &virtualFile{ | ||||
| 		EmbeddedFile: ef, | ||||
| 		offset:       0, | ||||
| 		closed:       false, | ||||
| 	} | ||||
| 	return vf | ||||
| } | ||||
|  | ||||
| //++ TODO check for nil pointers in all these methods. When so: return os.PathError with Err: os.ErrInvalid | ||||
|  | ||||
| func (vf *virtualFile) close() error { | ||||
| 	if vf.closed { | ||||
| 		return &os.PathError{ | ||||
| 			Op:   "close", | ||||
| 			Path: vf.EmbeddedFile.Filename, | ||||
| 			Err:  errors.New("already closed"), | ||||
| 		} | ||||
| 	} | ||||
| 	vf.EmbeddedFile = nil | ||||
| 	vf.closed = true | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (vf *virtualFile) stat() (os.FileInfo, error) { | ||||
| 	if vf.closed { | ||||
| 		return nil, &os.PathError{ | ||||
| 			Op:   "stat", | ||||
| 			Path: vf.EmbeddedFile.Filename, | ||||
| 			Err:  errors.New("bad file descriptor"), | ||||
| 		} | ||||
| 	} | ||||
| 	return (*embeddedFileInfo)(vf.EmbeddedFile), nil | ||||
| } | ||||
|  | ||||
| func (vf *virtualFile) readdir(count int) ([]os.FileInfo, error) { | ||||
| 	if vf.closed { | ||||
| 		return nil, &os.PathError{ | ||||
| 			Op:   "readdir", | ||||
| 			Path: vf.EmbeddedFile.Filename, | ||||
| 			Err:  errors.New("bad file descriptor"), | ||||
| 		} | ||||
| 	} | ||||
| 	//TODO: return proper error for a readdir() call on a file | ||||
| 	return nil, ErrNotImplemented | ||||
| } | ||||
|  | ||||
| func (vf *virtualFile) read(bts []byte) (int, error) { | ||||
| 	if vf.closed { | ||||
| 		return 0, &os.PathError{ | ||||
| 			Op:   "read", | ||||
| 			Path: vf.EmbeddedFile.Filename, | ||||
| 			Err:  errors.New("bad file descriptor"), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	end := vf.offset + int64(len(bts)) | ||||
|  | ||||
| 	if end >= int64(len(vf.Content)) { | ||||
| 		// end of file, so return what we have + EOF | ||||
| 		n := copy(bts, vf.Content[vf.offset:]) | ||||
| 		vf.offset = 0 | ||||
| 		return n, io.EOF | ||||
| 	} | ||||
|  | ||||
| 	n := copy(bts, vf.Content[vf.offset:end]) | ||||
| 	vf.offset += int64(n) | ||||
| 	return n, nil | ||||
|  | ||||
| } | ||||
|  | ||||
| func (vf *virtualFile) seek(offset int64, whence int) (int64, error) { | ||||
| 	if vf.closed { | ||||
| 		return 0, &os.PathError{ | ||||
| 			Op:   "seek", | ||||
| 			Path: vf.EmbeddedFile.Filename, | ||||
| 			Err:  errors.New("bad file descriptor"), | ||||
| 		} | ||||
| 	} | ||||
| 	var e error | ||||
|  | ||||
| 	//++ TODO: check if this is correct implementation for seek | ||||
| 	switch whence { | ||||
| 	case os.SEEK_SET: | ||||
| 		//++ check if new offset isn't out of bounds, set e when it is, then break out of switch | ||||
| 		vf.offset = offset | ||||
| 	case os.SEEK_CUR: | ||||
| 		//++ check if new offset isn't out of bounds, set e when it is, then break out of switch | ||||
| 		vf.offset += offset | ||||
| 	case os.SEEK_END: | ||||
| 		//++ check if new offset isn't out of bounds, set e when it is, then break out of switch | ||||
| 		vf.offset = int64(len(vf.EmbeddedFile.Content)) - offset | ||||
| 	} | ||||
|  | ||||
| 	if e != nil { | ||||
| 		return 0, &os.PathError{ | ||||
| 			Op:   "seek", | ||||
| 			Path: vf.Filename, | ||||
| 			Err:  e, | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return vf.offset, nil | ||||
| } | ||||
|  | ||||
| // virtualDir is a 'stateful' virtual directory. | ||||
| // virtualDir wraps an *EmbeddedDir for a call to Box.Open() and virtualizes 'closing'. | ||||
| // virtualDir is only internally visible and should be exposed through rice.File | ||||
| type virtualDir struct { | ||||
| 	*embedded.EmbeddedDir | ||||
| 	offset int // readdir position on the directory | ||||
| 	closed bool | ||||
| } | ||||
|  | ||||
| // create a new virtualDir for given EmbeddedDir | ||||
| func newVirtualDir(ed *embedded.EmbeddedDir) *virtualDir { | ||||
| 	vd := &virtualDir{ | ||||
| 		EmbeddedDir: ed, | ||||
| 		offset:      0, | ||||
| 		closed:      false, | ||||
| 	} | ||||
| 	return vd | ||||
| } | ||||
|  | ||||
| func (vd *virtualDir) close() error { | ||||
| 	//++ TODO: needs sync mutex? | ||||
| 	if vd.closed { | ||||
| 		return &os.PathError{ | ||||
| 			Op:   "close", | ||||
| 			Path: vd.EmbeddedDir.Filename, | ||||
| 			Err:  errors.New("already closed"), | ||||
| 		} | ||||
| 	} | ||||
| 	vd.closed = true | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (vd *virtualDir) stat() (os.FileInfo, error) { | ||||
| 	if vd.closed { | ||||
| 		return nil, &os.PathError{ | ||||
| 			Op:   "stat", | ||||
| 			Path: vd.EmbeddedDir.Filename, | ||||
| 			Err:  errors.New("bad file descriptor"), | ||||
| 		} | ||||
| 	} | ||||
| 	return (*embeddedDirInfo)(vd.EmbeddedDir), nil | ||||
| } | ||||
|  | ||||
| func (vd *virtualDir) readdir(n int) (fi []os.FileInfo, err error) { | ||||
|  | ||||
| 	if vd.closed { | ||||
| 		return nil, &os.PathError{ | ||||
| 			Op:   "readdir", | ||||
| 			Path: vd.EmbeddedDir.Filename, | ||||
| 			Err:  errors.New("bad file descriptor"), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Build up the array of our contents | ||||
| 	var files []os.FileInfo | ||||
|  | ||||
| 	// Add the child directories | ||||
| 	for _, child := range vd.ChildDirs { | ||||
| 		child.Filename = filepath.Base(child.Filename) | ||||
| 		files = append(files, (*embeddedDirInfo)(child)) | ||||
| 	} | ||||
|  | ||||
| 	// Add the child files | ||||
| 	for _, child := range vd.ChildFiles { | ||||
| 		child.Filename = filepath.Base(child.Filename) | ||||
| 		files = append(files, (*embeddedFileInfo)(child)) | ||||
| 	} | ||||
|  | ||||
| 	// Sort it by filename (lexical order) | ||||
| 	sort.Sort(SortByName(files)) | ||||
|  | ||||
| 	// Return all contents if that's what is requested | ||||
| 	if n <= 0 { | ||||
| 		vd.offset = 0 | ||||
| 		return files, nil | ||||
| 	} | ||||
|  | ||||
| 	// If user has requested past the end of our list | ||||
| 	// return what we can and send an EOF | ||||
| 	if vd.offset+n >= len(files) { | ||||
| 		offset := vd.offset | ||||
| 		vd.offset = 0 | ||||
| 		return files[offset:], io.EOF | ||||
| 	} | ||||
|  | ||||
| 	offset := vd.offset | ||||
| 	vd.offset += n | ||||
| 	return files[offset : offset+n], nil | ||||
|  | ||||
| } | ||||
|  | ||||
| func (vd *virtualDir) read(bts []byte) (int, error) { | ||||
| 	if vd.closed { | ||||
| 		return 0, &os.PathError{ | ||||
| 			Op:   "read", | ||||
| 			Path: vd.EmbeddedDir.Filename, | ||||
| 			Err:  errors.New("bad file descriptor"), | ||||
| 		} | ||||
| 	} | ||||
| 	return 0, &os.PathError{ | ||||
| 		Op:   "read", | ||||
| 		Path: vd.EmbeddedDir.Filename, | ||||
| 		Err:  errors.New("is a directory"), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (vd *virtualDir) seek(offset int64, whence int) (int64, error) { | ||||
| 	if vd.closed { | ||||
| 		return 0, &os.PathError{ | ||||
| 			Op:   "seek", | ||||
| 			Path: vd.EmbeddedDir.Filename, | ||||
| 			Err:  errors.New("bad file descriptor"), | ||||
| 		} | ||||
| 	} | ||||
| 	return 0, &os.PathError{ | ||||
| 		Op:   "seek", | ||||
| 		Path: vd.Filename, | ||||
| 		Err:  errors.New("is a directory"), | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										122
									
								
								vendor/github.com/GeertJohan/go.rice/walk.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										122
									
								
								vendor/github.com/GeertJohan/go.rice/walk.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,122 +0,0 @@ | ||||
| package rice | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // Walk is like filepath.Walk() | ||||
| // Visit http://golang.org/pkg/path/filepath/#Walk for more information | ||||
| func (b *Box) Walk(path string, walkFn filepath.WalkFunc) error { | ||||
|  | ||||
| 	pathFile, err := b.Open(path) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer pathFile.Close() | ||||
|  | ||||
| 	pathInfo, err := pathFile.Stat() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if b.IsAppended() || b.IsEmbedded() { | ||||
| 		return b.walk(path, pathInfo, walkFn) | ||||
| 	} | ||||
|  | ||||
| 	// We don't have any embedded or appended box so use live filesystem mode | ||||
| 	return filepath.Walk(b.absolutePath+string(os.PathSeparator)+path, func(path string, info os.FileInfo, err error) error { | ||||
|  | ||||
| 		// Strip out the box name from the returned paths | ||||
| 		path = strings.TrimPrefix(path, b.absolutePath+string(os.PathSeparator)) | ||||
| 		return walkFn(path, info, err) | ||||
|  | ||||
| 	}) | ||||
|  | ||||
| } | ||||
|  | ||||
| // walk recursively descends path. | ||||
| // See walk() in $GOROOT/src/pkg/path/filepath/path.go | ||||
| func (b *Box) walk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error { | ||||
|  | ||||
| 	err := walkFn(path, info, nil) | ||||
| 	if err != nil { | ||||
| 		if info.IsDir() && err == filepath.SkipDir { | ||||
| 			return nil | ||||
| 		} | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if !info.IsDir() { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	names, err := b.readDirNames(path) | ||||
| 	if err != nil { | ||||
| 		return walkFn(path, info, err) | ||||
| 	} | ||||
|  | ||||
| 	for _, name := range names { | ||||
|  | ||||
| 		filename := filepath.Join(path, name) | ||||
| 		fileObject, err := b.Open(filename) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		defer fileObject.Close() | ||||
|  | ||||
| 		fileInfo, err := fileObject.Stat() | ||||
| 		if err != nil { | ||||
| 			if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir { | ||||
| 				return err | ||||
| 			} | ||||
| 		} else { | ||||
| 			err = b.walk(filename, fileInfo, walkFn) | ||||
| 			if err != nil { | ||||
| 				if !fileInfo.IsDir() || err != filepath.SkipDir { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
|  | ||||
| } | ||||
|  | ||||
| // readDirNames reads the directory named by path and returns a sorted list of directory entries. | ||||
| // See readDirNames() in $GOROOT/pkg/path/filepath/path.go | ||||
| func (b *Box) readDirNames(path string) ([]string, error) { | ||||
|  | ||||
| 	f, err := b.Open(path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	stat, err := f.Stat() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if !stat.IsDir() { | ||||
| 		return nil, nil | ||||
| 	} | ||||
|  | ||||
| 	infos, err := f.Readdir(0) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var names []string | ||||
|  | ||||
| 	for _, info := range infos { | ||||
| 		names = append(names, info.Name()) | ||||
| 	} | ||||
|  | ||||
| 	sort.Strings(names) | ||||
| 	return names, nil | ||||
|  | ||||
| } | ||||
							
								
								
									
										22
									
								
								vendor/github.com/Philipp15b/go-steam/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/Philipp15b/go-steam/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| # Compiled Object files, Static and Dynamic libs (Shared Objects) | ||||
| *.o | ||||
| *.a | ||||
| *.so | ||||
|  | ||||
| # Folders | ||||
| _obj | ||||
| _test | ||||
|  | ||||
| # Architecture specific extensions/prefixes | ||||
| *.[568vq] | ||||
| [568vq].out | ||||
|  | ||||
| *.cgo1.go | ||||
| *.cgo2.c | ||||
| _cgo_defun.c | ||||
| _cgo_gotypes.go | ||||
| _cgo_export.* | ||||
|  | ||||
| _testmain.go | ||||
|  | ||||
| *.exe | ||||
							
								
								
									
										3
									
								
								vendor/github.com/Philipp15b/go-steam/.gitmodules
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/Philipp15b/go-steam/.gitmodules
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| [submodule "generator/SteamKit"] | ||||
| 	path = generator/SteamKit | ||||
| 	url = https://github.com/Philipp15b/SteamKit.git | ||||
							
								
								
									
										64
									
								
								vendor/github.com/Philipp15b/go-steam/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								vendor/github.com/Philipp15b/go-steam/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| # Steam for Go | ||||
|  | ||||
| This library implements Steam's protocol to allow automation of different actions on Steam without running an actual Steam client. It is based on [SteamKit2](https://github.com/SteamRE/SteamKit), a .NET library. | ||||
|  | ||||
| In addition, it contains APIs to Steam Community features, like trade offers and inventories. | ||||
|  | ||||
| Some of the currently implemented features: | ||||
|  | ||||
|   * Trading and trade offers, including inventories and notifications | ||||
|   * Friend and group management | ||||
|   * Chatting with friends | ||||
|   * Persona states (online, offline, looking to trade, etc.) | ||||
|   * SteamGuard with two-factor authentication | ||||
|   * Team Fortress 2: Crafting, moving, naming and deleting items | ||||
|  | ||||
| If this is useful to you, there's also the [go-steamapi](https://github.com/Philipp15b/go-steamapi) package that wraps some of the official Steam Web API's types. | ||||
|  | ||||
| ## Installation | ||||
|  | ||||
|     go get github.com/Philipp15b/go-steam | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| You can view the documentation with the [`godoc`](http://golang.org/cmd/godoc) tool or | ||||
| [online on godoc.org](http://godoc.org/github.com/Philipp15b/go-steam). | ||||
|  | ||||
| You should also take a look at the following sub-packages: | ||||
|  | ||||
|   * [`gsbot`](http://godoc.org/github.com/Philipp15b/go-steam/gsbot) utilites that make writing bots easier | ||||
|   * [example bot](http://godoc.org/github.com/Philipp15b/go-steam/gsbot/gsbot) and [its source code](https://github.com/Philipp15b/go-steam/blob/master/gsbot/gsbot/gsbot.go) | ||||
|   * [`trade`](http://godoc.org/github.com/Philipp15b/go-steam/trade) for trading | ||||
|   * [`tradeoffer`](http://godoc.org/github.com/Philipp15b/go-steam/tradeoffer) for trade offers | ||||
|   * [`economy/inventory`](http://godoc.org/github.com/Philipp15b/go-steam/economy/inventory) for inventories | ||||
|   * [`tf2`](http://godoc.org/github.com/Philipp15b/go-steam/tf2) for Team Fortress 2 related things | ||||
|  | ||||
| ## Working with go-steam | ||||
|  | ||||
| Whether you want to develop your own Steam bot or directly work on go-steam itself, there are are few things to know. | ||||
|  | ||||
|  * If something is not working, check first if the same operation works (under the same conditions!) in the Steam client on that account. Maybe there's something go-steam doesn't handle correctly or you're missing a warning that's not obviously shown in go-steam. This is particularly important when working with trading since there are [restrictions](https://support.steampowered.com/kb_article.php?ref=1047-edfm-2932), for example newly authorized devices will not be able to trade for seven days. | ||||
|  * Since Steam does not maintain a public API for most of the things go-steam implements, you can expect that sometimes things break randomly. Especially the `trade` and `tradeoffer` packages have been affected in the past. | ||||
|  * Always gather as much information as possible. When you file an issue, be as precise and complete as you can. This makes debugging way easier. | ||||
|  * If you haven't noticed yet, expect to find lots of things out yourself. Debugging can be complicated and Steam's internals are too. | ||||
|  * Sometimes things break and other [SteamKit ports](https://github.com/SteamRE/SteamKit/wiki/Ports) are fixed already. Maybe take a look what people are saying over there? There's also the [SteamKit IRC channel](https://github.com/SteamRE/SteamKit/wiki#contact). | ||||
|  | ||||
| ## Updating go-steam to a new SteamKit version | ||||
|  | ||||
| To update go-steam to a new version of SteamKit, do the following: | ||||
|  | ||||
| 	go get github.com/golang/protobuf/protoc-gen-go/ | ||||
|     git submodule init && git submodule update | ||||
|     cd generator | ||||
|     go run generator.go clean proto steamlang | ||||
|  | ||||
| Make sure that `$GOPATH/bin` / `protoc-gen-go` is in your `$PATH`. You'll also need [`protoc`](https://developers.google.com/protocol-buffers/docs/downloads), the protocol buffer compiler. At the moment, we use Protocol Buffers 2.6.1 with `proco-gen-go`-[2402d76](https://github.com/golang/protobuf/tree/2402d76f3d41f928c7902a765dfc872356dd3aad). | ||||
|  | ||||
| To compile the Steam Language files, you also need the [.NET Framework](https://www.microsoft.com/net/downloads) | ||||
| on Windows or [mono](http://www.go-mono.com/mono-downloads/download.html) on other operating systems. | ||||
|  | ||||
| Apply the protocol changes where necessary. | ||||
|  | ||||
| ## License | ||||
|  | ||||
| Steam for Go is licensed under the New BSD License. More information can be found in LICENSE.txt. | ||||
							
								
								
									
										35
									
								
								vendor/github.com/Philipp15b/go-steam/community/community.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										35
									
								
								vendor/github.com/Philipp15b/go-steam/community/community.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,35 +0,0 @@ | ||||
| package community | ||||
|  | ||||
| import ( | ||||
| 	"net/http" | ||||
| 	"net/http/cookiejar" | ||||
| 	"net/url" | ||||
| ) | ||||
|  | ||||
| const cookiePath = "https://steamcommunity.com/" | ||||
|  | ||||
| func SetCookies(client *http.Client, sessionId, steamLogin, steamLoginSecure string) { | ||||
| 	if client.Jar == nil { | ||||
| 		client.Jar, _ = cookiejar.New(new(cookiejar.Options)) | ||||
| 	} | ||||
| 	base, err := url.Parse(cookiePath) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	client.Jar.SetCookies(base, []*http.Cookie{ | ||||
| 		// It seems that, for some reason, Steam tries to URL-decode the cookie. | ||||
| 		&http.Cookie{ | ||||
| 			Name:  "sessionid", | ||||
| 			Value: url.QueryEscape(sessionId), | ||||
| 		}, | ||||
| 		// steamLogin is already URL-encoded. | ||||
| 		&http.Cookie{ | ||||
| 			Name:  "steamLogin", | ||||
| 			Value: steamLogin, | ||||
| 		}, | ||||
| 		&http.Cookie{ | ||||
| 			Name:  "steamLoginSecure", | ||||
| 			Value: steamLoginSecure, | ||||
| 		}, | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										3651
									
								
								vendor/github.com/Philipp15b/go-steam/dota/protocol/protobuf/base.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3651
									
								
								vendor/github.com/Philipp15b/go-steam/dota/protocol/protobuf/base.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										18413
									
								
								vendor/github.com/Philipp15b/go-steam/dota/protocol/protobuf/dota_client.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18413
									
								
								vendor/github.com/Philipp15b/go-steam/dota/protocol/protobuf/dota_client.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										6123
									
								
								vendor/github.com/Philipp15b/go-steam/dota/protocol/protobuf/dota_client_fantasy.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6123
									
								
								vendor/github.com/Philipp15b/go-steam/dota/protocol/protobuf/dota_client_fantasy.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										10997
									
								
								vendor/github.com/Philipp15b/go-steam/dota/protocol/protobuf/dota_common.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10997
									
								
								vendor/github.com/Philipp15b/go-steam/dota/protocol/protobuf/dota_common.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4441
									
								
								vendor/github.com/Philipp15b/go-steam/dota/protocol/protobuf/econ.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4441
									
								
								vendor/github.com/Philipp15b/go-steam/dota/protocol/protobuf/econ.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1825
									
								
								vendor/github.com/Philipp15b/go-steam/dota/protocol/protobuf/gcsdk.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1825
									
								
								vendor/github.com/Philipp15b/go-steam/dota/protocol/protobuf/gcsdk.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										579
									
								
								vendor/github.com/Philipp15b/go-steam/dota/protocol/protobuf/system.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										579
									
								
								vendor/github.com/Philipp15b/go-steam/dota/protocol/protobuf/system.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,579 +0,0 @@ | ||||
| // Code generated by protoc-gen-go. | ||||
| // source: gcsystemmsgs.proto | ||||
| // DO NOT EDIT! | ||||
|  | ||||
| package protobuf | ||||
|  | ||||
| import proto "github.com/golang/protobuf/proto" | ||||
| import fmt "fmt" | ||||
| import math "math" | ||||
|  | ||||
| // Reference imports to suppress errors if they are not otherwise used. | ||||
| var _ = proto.Marshal | ||||
| var _ = fmt.Errorf | ||||
| var _ = math.Inf | ||||
|  | ||||
| // This is a compile-time assertion to ensure that this generated file | ||||
| // is compatible with the proto package protobuf is being compiled against. | ||||
| const _ = proto.ProtoPackageIsVersion1 | ||||
|  | ||||
| type EGCSystemMsg int32 | ||||
|  | ||||
| const ( | ||||
| 	EGCSystemMsg_k_EGCMsgInvalid                           EGCSystemMsg = 0 | ||||
| 	EGCSystemMsg_k_EGCMsgMulti                             EGCSystemMsg = 1 | ||||
| 	EGCSystemMsg_k_EGCMsgGenericReply                      EGCSystemMsg = 10 | ||||
| 	EGCSystemMsg_k_EGCMsgSystemBase                        EGCSystemMsg = 50 | ||||
| 	EGCSystemMsg_k_EGCMsgAchievementAwarded                EGCSystemMsg = 51 | ||||
| 	EGCSystemMsg_k_EGCMsgConCommand                        EGCSystemMsg = 52 | ||||
| 	EGCSystemMsg_k_EGCMsgStartPlaying                      EGCSystemMsg = 53 | ||||
| 	EGCSystemMsg_k_EGCMsgStopPlaying                       EGCSystemMsg = 54 | ||||
| 	EGCSystemMsg_k_EGCMsgStartGameserver                   EGCSystemMsg = 55 | ||||
| 	EGCSystemMsg_k_EGCMsgStopGameserver                    EGCSystemMsg = 56 | ||||
| 	EGCSystemMsg_k_EGCMsgWGRequest                         EGCSystemMsg = 57 | ||||
| 	EGCSystemMsg_k_EGCMsgWGResponse                        EGCSystemMsg = 58 | ||||
| 	EGCSystemMsg_k_EGCMsgGetUserGameStatsSchema            EGCSystemMsg = 59 | ||||
| 	EGCSystemMsg_k_EGCMsgGetUserGameStatsSchemaResponse    EGCSystemMsg = 60 | ||||
| 	EGCSystemMsg_k_EGCMsgGetUserStatsDEPRECATED            EGCSystemMsg = 61 | ||||
| 	EGCSystemMsg_k_EGCMsgGetUserStatsResponse              EGCSystemMsg = 62 | ||||
| 	EGCSystemMsg_k_EGCMsgAppInfoUpdated                    EGCSystemMsg = 63 | ||||
| 	EGCSystemMsg_k_EGCMsgValidateSession                   EGCSystemMsg = 64 | ||||
| 	EGCSystemMsg_k_EGCMsgValidateSessionResponse           EGCSystemMsg = 65 | ||||
| 	EGCSystemMsg_k_EGCMsgLookupAccountFromInput            EGCSystemMsg = 66 | ||||
| 	EGCSystemMsg_k_EGCMsgSendHTTPRequest                   EGCSystemMsg = 67 | ||||
| 	EGCSystemMsg_k_EGCMsgSendHTTPRequestResponse           EGCSystemMsg = 68 | ||||
| 	EGCSystemMsg_k_EGCMsgPreTestSetup                      EGCSystemMsg = 69 | ||||
| 	EGCSystemMsg_k_EGCMsgRecordSupportAction               EGCSystemMsg = 70 | ||||
| 	EGCSystemMsg_k_EGCMsgGetAccountDetails_DEPRECATED      EGCSystemMsg = 71 | ||||
| 	EGCSystemMsg_k_EGCMsgReceiveInterAppMessage            EGCSystemMsg = 73 | ||||
| 	EGCSystemMsg_k_EGCMsgFindAccounts                      EGCSystemMsg = 74 | ||||
| 	EGCSystemMsg_k_EGCMsgPostAlert                         EGCSystemMsg = 75 | ||||
| 	EGCSystemMsg_k_EGCMsgGetLicenses                       EGCSystemMsg = 76 | ||||
| 	EGCSystemMsg_k_EGCMsgGetUserStats                      EGCSystemMsg = 77 | ||||
| 	EGCSystemMsg_k_EGCMsgGetCommands                       EGCSystemMsg = 78 | ||||
| 	EGCSystemMsg_k_EGCMsgGetCommandsResponse               EGCSystemMsg = 79 | ||||
| 	EGCSystemMsg_k_EGCMsgAddFreeLicense                    EGCSystemMsg = 80 | ||||
| 	EGCSystemMsg_k_EGCMsgAddFreeLicenseResponse            EGCSystemMsg = 81 | ||||
| 	EGCSystemMsg_k_EGCMsgGetIPLocation                     EGCSystemMsg = 82 | ||||
| 	EGCSystemMsg_k_EGCMsgGetIPLocationResponse             EGCSystemMsg = 83 | ||||
| 	EGCSystemMsg_k_EGCMsgSystemStatsSchema                 EGCSystemMsg = 84 | ||||
| 	EGCSystemMsg_k_EGCMsgGetSystemStats                    EGCSystemMsg = 85 | ||||
| 	EGCSystemMsg_k_EGCMsgGetSystemStatsResponse            EGCSystemMsg = 86 | ||||
| 	EGCSystemMsg_k_EGCMsgSendEmail                         EGCSystemMsg = 87 | ||||
| 	EGCSystemMsg_k_EGCMsgSendEmailResponse                 EGCSystemMsg = 88 | ||||
| 	EGCSystemMsg_k_EGCMsgGetEmailTemplate                  EGCSystemMsg = 89 | ||||
| 	EGCSystemMsg_k_EGCMsgGetEmailTemplateResponse          EGCSystemMsg = 90 | ||||
| 	EGCSystemMsg_k_EGCMsgGrantGuestPass                    EGCSystemMsg = 91 | ||||
| 	EGCSystemMsg_k_EGCMsgGrantGuestPassResponse            EGCSystemMsg = 92 | ||||
| 	EGCSystemMsg_k_EGCMsgGetAccountDetails                 EGCSystemMsg = 93 | ||||
| 	EGCSystemMsg_k_EGCMsgGetAccountDetailsResponse         EGCSystemMsg = 94 | ||||
| 	EGCSystemMsg_k_EGCMsgGetPersonaNames                   EGCSystemMsg = 95 | ||||
| 	EGCSystemMsg_k_EGCMsgGetPersonaNamesResponse           EGCSystemMsg = 96 | ||||
| 	EGCSystemMsg_k_EGCMsgMultiplexMsg                      EGCSystemMsg = 97 | ||||
| 	EGCSystemMsg_k_EGCMsgWebAPIRegisterInterfaces          EGCSystemMsg = 101 | ||||
| 	EGCSystemMsg_k_EGCMsgWebAPIJobRequest                  EGCSystemMsg = 102 | ||||
| 	EGCSystemMsg_k_EGCMsgWebAPIJobRequestHttpResponse      EGCSystemMsg = 104 | ||||
| 	EGCSystemMsg_k_EGCMsgWebAPIJobRequestForwardResponse   EGCSystemMsg = 105 | ||||
| 	EGCSystemMsg_k_EGCMsgMemCachedGet                      EGCSystemMsg = 200 | ||||
| 	EGCSystemMsg_k_EGCMsgMemCachedGetResponse              EGCSystemMsg = 201 | ||||
| 	EGCSystemMsg_k_EGCMsgMemCachedSet                      EGCSystemMsg = 202 | ||||
| 	EGCSystemMsg_k_EGCMsgMemCachedDelete                   EGCSystemMsg = 203 | ||||
| 	EGCSystemMsg_k_EGCMsgMemCachedStats                    EGCSystemMsg = 204 | ||||
| 	EGCSystemMsg_k_EGCMsgMemCachedStatsResponse            EGCSystemMsg = 205 | ||||
| 	EGCSystemMsg_k_EGCMsgSQLStats                          EGCSystemMsg = 210 | ||||
| 	EGCSystemMsg_k_EGCMsgSQLStatsResponse                  EGCSystemMsg = 211 | ||||
| 	EGCSystemMsg_k_EGCMsgMasterSetDirectory                EGCSystemMsg = 220 | ||||
| 	EGCSystemMsg_k_EGCMsgMasterSetDirectoryResponse        EGCSystemMsg = 221 | ||||
| 	EGCSystemMsg_k_EGCMsgMasterSetWebAPIRouting            EGCSystemMsg = 222 | ||||
| 	EGCSystemMsg_k_EGCMsgMasterSetWebAPIRoutingResponse    EGCSystemMsg = 223 | ||||
| 	EGCSystemMsg_k_EGCMsgMasterSetClientMsgRouting         EGCSystemMsg = 224 | ||||
| 	EGCSystemMsg_k_EGCMsgMasterSetClientMsgRoutingResponse EGCSystemMsg = 225 | ||||
| 	EGCSystemMsg_k_EGCMsgSetOptions                        EGCSystemMsg = 226 | ||||
| 	EGCSystemMsg_k_EGCMsgSetOptionsResponse                EGCSystemMsg = 227 | ||||
| 	EGCSystemMsg_k_EGCMsgSystemBase2                       EGCSystemMsg = 500 | ||||
| 	EGCSystemMsg_k_EGCMsgGetPurchaseTrustStatus            EGCSystemMsg = 501 | ||||
| 	EGCSystemMsg_k_EGCMsgGetPurchaseTrustStatusResponse    EGCSystemMsg = 502 | ||||
| 	EGCSystemMsg_k_EGCMsgUpdateSession                     EGCSystemMsg = 503 | ||||
| 	EGCSystemMsg_k_EGCMsgGCAccountVacStatusChange          EGCSystemMsg = 504 | ||||
| 	EGCSystemMsg_k_EGCMsgCheckFriendship                   EGCSystemMsg = 505 | ||||
| 	EGCSystemMsg_k_EGCMsgCheckFriendshipResponse           EGCSystemMsg = 506 | ||||
| 	EGCSystemMsg_k_EGCMsgGetPartnerAccountLink             EGCSystemMsg = 507 | ||||
| 	EGCSystemMsg_k_EGCMsgGetPartnerAccountLinkResponse     EGCSystemMsg = 508 | ||||
| 	EGCSystemMsg_k_EGCMsgVSReportedSuspiciousActivity      EGCSystemMsg = 509 | ||||
| 	EGCSystemMsg_k_EGCMsgDPPartnerMicroTxns                EGCSystemMsg = 512 | ||||
| 	EGCSystemMsg_k_EGCMsgDPPartnerMicroTxnsResponse        EGCSystemMsg = 513 | ||||
| 	EGCSystemMsg_k_EGCMsgGetIPASN                          EGCSystemMsg = 514 | ||||
| 	EGCSystemMsg_k_EGCMsgGetIPASNResponse                  EGCSystemMsg = 515 | ||||
| 	EGCSystemMsg_k_EGCMsgGetAppFriendsList                 EGCSystemMsg = 516 | ||||
| 	EGCSystemMsg_k_EGCMsgGetAppFriendsListResponse         EGCSystemMsg = 517 | ||||
| ) | ||||
|  | ||||
| var EGCSystemMsg_name = map[int32]string{ | ||||
| 	0:   "k_EGCMsgInvalid", | ||||
| 	1:   "k_EGCMsgMulti", | ||||
| 	10:  "k_EGCMsgGenericReply", | ||||
| 	50:  "k_EGCMsgSystemBase", | ||||
| 	51:  "k_EGCMsgAchievementAwarded", | ||||
| 	52:  "k_EGCMsgConCommand", | ||||
| 	53:  "k_EGCMsgStartPlaying", | ||||
| 	54:  "k_EGCMsgStopPlaying", | ||||
| 	55:  "k_EGCMsgStartGameserver", | ||||
| 	56:  "k_EGCMsgStopGameserver", | ||||
| 	57:  "k_EGCMsgWGRequest", | ||||
| 	58:  "k_EGCMsgWGResponse", | ||||
| 	59:  "k_EGCMsgGetUserGameStatsSchema", | ||||
| 	60:  "k_EGCMsgGetUserGameStatsSchemaResponse", | ||||
| 	61:  "k_EGCMsgGetUserStatsDEPRECATED", | ||||
| 	62:  "k_EGCMsgGetUserStatsResponse", | ||||
| 	63:  "k_EGCMsgAppInfoUpdated", | ||||
| 	64:  "k_EGCMsgValidateSession", | ||||
| 	65:  "k_EGCMsgValidateSessionResponse", | ||||
| 	66:  "k_EGCMsgLookupAccountFromInput", | ||||
| 	67:  "k_EGCMsgSendHTTPRequest", | ||||
| 	68:  "k_EGCMsgSendHTTPRequestResponse", | ||||
| 	69:  "k_EGCMsgPreTestSetup", | ||||
| 	70:  "k_EGCMsgRecordSupportAction", | ||||
| 	71:  "k_EGCMsgGetAccountDetails_DEPRECATED", | ||||
| 	73:  "k_EGCMsgReceiveInterAppMessage", | ||||
| 	74:  "k_EGCMsgFindAccounts", | ||||
| 	75:  "k_EGCMsgPostAlert", | ||||
| 	76:  "k_EGCMsgGetLicenses", | ||||
| 	77:  "k_EGCMsgGetUserStats", | ||||
| 	78:  "k_EGCMsgGetCommands", | ||||
| 	79:  "k_EGCMsgGetCommandsResponse", | ||||
| 	80:  "k_EGCMsgAddFreeLicense", | ||||
| 	81:  "k_EGCMsgAddFreeLicenseResponse", | ||||
| 	82:  "k_EGCMsgGetIPLocation", | ||||
| 	83:  "k_EGCMsgGetIPLocationResponse", | ||||
| 	84:  "k_EGCMsgSystemStatsSchema", | ||||
| 	85:  "k_EGCMsgGetSystemStats", | ||||
| 	86:  "k_EGCMsgGetSystemStatsResponse", | ||||
| 	87:  "k_EGCMsgSendEmail", | ||||
| 	88:  "k_EGCMsgSendEmailResponse", | ||||
| 	89:  "k_EGCMsgGetEmailTemplate", | ||||
| 	90:  "k_EGCMsgGetEmailTemplateResponse", | ||||
| 	91:  "k_EGCMsgGrantGuestPass", | ||||
| 	92:  "k_EGCMsgGrantGuestPassResponse", | ||||
| 	93:  "k_EGCMsgGetAccountDetails", | ||||
| 	94:  "k_EGCMsgGetAccountDetailsResponse", | ||||
| 	95:  "k_EGCMsgGetPersonaNames", | ||||
| 	96:  "k_EGCMsgGetPersonaNamesResponse", | ||||
| 	97:  "k_EGCMsgMultiplexMsg", | ||||
| 	101: "k_EGCMsgWebAPIRegisterInterfaces", | ||||
| 	102: "k_EGCMsgWebAPIJobRequest", | ||||
| 	104: "k_EGCMsgWebAPIJobRequestHttpResponse", | ||||
| 	105: "k_EGCMsgWebAPIJobRequestForwardResponse", | ||||
| 	200: "k_EGCMsgMemCachedGet", | ||||
| 	201: "k_EGCMsgMemCachedGetResponse", | ||||
| 	202: "k_EGCMsgMemCachedSet", | ||||
| 	203: "k_EGCMsgMemCachedDelete", | ||||
| 	204: "k_EGCMsgMemCachedStats", | ||||
| 	205: "k_EGCMsgMemCachedStatsResponse", | ||||
| 	210: "k_EGCMsgSQLStats", | ||||
| 	211: "k_EGCMsgSQLStatsResponse", | ||||
| 	220: "k_EGCMsgMasterSetDirectory", | ||||
| 	221: "k_EGCMsgMasterSetDirectoryResponse", | ||||
| 	222: "k_EGCMsgMasterSetWebAPIRouting", | ||||
| 	223: "k_EGCMsgMasterSetWebAPIRoutingResponse", | ||||
| 	224: "k_EGCMsgMasterSetClientMsgRouting", | ||||
| 	225: "k_EGCMsgMasterSetClientMsgRoutingResponse", | ||||
| 	226: "k_EGCMsgSetOptions", | ||||
| 	227: "k_EGCMsgSetOptionsResponse", | ||||
| 	500: "k_EGCMsgSystemBase2", | ||||
| 	501: "k_EGCMsgGetPurchaseTrustStatus", | ||||
| 	502: "k_EGCMsgGetPurchaseTrustStatusResponse", | ||||
| 	503: "k_EGCMsgUpdateSession", | ||||
| 	504: "k_EGCMsgGCAccountVacStatusChange", | ||||
| 	505: "k_EGCMsgCheckFriendship", | ||||
| 	506: "k_EGCMsgCheckFriendshipResponse", | ||||
| 	507: "k_EGCMsgGetPartnerAccountLink", | ||||
| 	508: "k_EGCMsgGetPartnerAccountLinkResponse", | ||||
| 	509: "k_EGCMsgVSReportedSuspiciousActivity", | ||||
| 	512: "k_EGCMsgDPPartnerMicroTxns", | ||||
| 	513: "k_EGCMsgDPPartnerMicroTxnsResponse", | ||||
| 	514: "k_EGCMsgGetIPASN", | ||||
| 	515: "k_EGCMsgGetIPASNResponse", | ||||
| 	516: "k_EGCMsgGetAppFriendsList", | ||||
| 	517: "k_EGCMsgGetAppFriendsListResponse", | ||||
| } | ||||
| var EGCSystemMsg_value = map[string]int32{ | ||||
| 	"k_EGCMsgInvalid":                           0, | ||||
| 	"k_EGCMsgMulti":                             1, | ||||
| 	"k_EGCMsgGenericReply":                      10, | ||||
| 	"k_EGCMsgSystemBase":                        50, | ||||
| 	"k_EGCMsgAchievementAwarded":                51, | ||||
| 	"k_EGCMsgConCommand":                        52, | ||||
| 	"k_EGCMsgStartPlaying":                      53, | ||||
| 	"k_EGCMsgStopPlaying":                       54, | ||||
| 	"k_EGCMsgStartGameserver":                   55, | ||||
| 	"k_EGCMsgStopGameserver":                    56, | ||||
| 	"k_EGCMsgWGRequest":                         57, | ||||
| 	"k_EGCMsgWGResponse":                        58, | ||||
| 	"k_EGCMsgGetUserGameStatsSchema":            59, | ||||
| 	"k_EGCMsgGetUserGameStatsSchemaResponse":    60, | ||||
| 	"k_EGCMsgGetUserStatsDEPRECATED":            61, | ||||
| 	"k_EGCMsgGetUserStatsResponse":              62, | ||||
| 	"k_EGCMsgAppInfoUpdated":                    63, | ||||
| 	"k_EGCMsgValidateSession":                   64, | ||||
| 	"k_EGCMsgValidateSessionResponse":           65, | ||||
| 	"k_EGCMsgLookupAccountFromInput":            66, | ||||
| 	"k_EGCMsgSendHTTPRequest":                   67, | ||||
| 	"k_EGCMsgSendHTTPRequestResponse":           68, | ||||
| 	"k_EGCMsgPreTestSetup":                      69, | ||||
| 	"k_EGCMsgRecordSupportAction":               70, | ||||
| 	"k_EGCMsgGetAccountDetails_DEPRECATED":      71, | ||||
| 	"k_EGCMsgReceiveInterAppMessage":            73, | ||||
| 	"k_EGCMsgFindAccounts":                      74, | ||||
| 	"k_EGCMsgPostAlert":                         75, | ||||
| 	"k_EGCMsgGetLicenses":                       76, | ||||
| 	"k_EGCMsgGetUserStats":                      77, | ||||
| 	"k_EGCMsgGetCommands":                       78, | ||||
| 	"k_EGCMsgGetCommandsResponse":               79, | ||||
| 	"k_EGCMsgAddFreeLicense":                    80, | ||||
| 	"k_EGCMsgAddFreeLicenseResponse":            81, | ||||
| 	"k_EGCMsgGetIPLocation":                     82, | ||||
| 	"k_EGCMsgGetIPLocationResponse":             83, | ||||
| 	"k_EGCMsgSystemStatsSchema":                 84, | ||||
| 	"k_EGCMsgGetSystemStats":                    85, | ||||
| 	"k_EGCMsgGetSystemStatsResponse":            86, | ||||
| 	"k_EGCMsgSendEmail":                         87, | ||||
| 	"k_EGCMsgSendEmailResponse":                 88, | ||||
| 	"k_EGCMsgGetEmailTemplate":                  89, | ||||
| 	"k_EGCMsgGetEmailTemplateResponse":          90, | ||||
| 	"k_EGCMsgGrantGuestPass":                    91, | ||||
| 	"k_EGCMsgGrantGuestPassResponse":            92, | ||||
| 	"k_EGCMsgGetAccountDetails":                 93, | ||||
| 	"k_EGCMsgGetAccountDetailsResponse":         94, | ||||
| 	"k_EGCMsgGetPersonaNames":                   95, | ||||
| 	"k_EGCMsgGetPersonaNamesResponse":           96, | ||||
| 	"k_EGCMsgMultiplexMsg":                      97, | ||||
| 	"k_EGCMsgWebAPIRegisterInterfaces":          101, | ||||
| 	"k_EGCMsgWebAPIJobRequest":                  102, | ||||
| 	"k_EGCMsgWebAPIJobRequestHttpResponse":      104, | ||||
| 	"k_EGCMsgWebAPIJobRequestForwardResponse":   105, | ||||
| 	"k_EGCMsgMemCachedGet":                      200, | ||||
| 	"k_EGCMsgMemCachedGetResponse":              201, | ||||
| 	"k_EGCMsgMemCachedSet":                      202, | ||||
| 	"k_EGCMsgMemCachedDelete":                   203, | ||||
| 	"k_EGCMsgMemCachedStats":                    204, | ||||
| 	"k_EGCMsgMemCachedStatsResponse":            205, | ||||
| 	"k_EGCMsgSQLStats":                          210, | ||||
| 	"k_EGCMsgSQLStatsResponse":                  211, | ||||
| 	"k_EGCMsgMasterSetDirectory":                220, | ||||
| 	"k_EGCMsgMasterSetDirectoryResponse":        221, | ||||
| 	"k_EGCMsgMasterSetWebAPIRouting":            222, | ||||
| 	"k_EGCMsgMasterSetWebAPIRoutingResponse":    223, | ||||
| 	"k_EGCMsgMasterSetClientMsgRouting":         224, | ||||
| 	"k_EGCMsgMasterSetClientMsgRoutingResponse": 225, | ||||
| 	"k_EGCMsgSetOptions":                        226, | ||||
| 	"k_EGCMsgSetOptionsResponse":                227, | ||||
| 	"k_EGCMsgSystemBase2":                       500, | ||||
| 	"k_EGCMsgGetPurchaseTrustStatus":            501, | ||||
| 	"k_EGCMsgGetPurchaseTrustStatusResponse":    502, | ||||
| 	"k_EGCMsgUpdateSession":                     503, | ||||
| 	"k_EGCMsgGCAccountVacStatusChange":          504, | ||||
| 	"k_EGCMsgCheckFriendship":                   505, | ||||
| 	"k_EGCMsgCheckFriendshipResponse":           506, | ||||
| 	"k_EGCMsgGetPartnerAccountLink":             507, | ||||
| 	"k_EGCMsgGetPartnerAccountLinkResponse":     508, | ||||
| 	"k_EGCMsgVSReportedSuspiciousActivity":      509, | ||||
| 	"k_EGCMsgDPPartnerMicroTxns":                512, | ||||
| 	"k_EGCMsgDPPartnerMicroTxnsResponse":        513, | ||||
| 	"k_EGCMsgGetIPASN":                          514, | ||||
| 	"k_EGCMsgGetIPASNResponse":                  515, | ||||
| 	"k_EGCMsgGetAppFriendsList":                 516, | ||||
| 	"k_EGCMsgGetAppFriendsListResponse":         517, | ||||
| } | ||||
|  | ||||
| func (x EGCSystemMsg) Enum() *EGCSystemMsg { | ||||
| 	p := new(EGCSystemMsg) | ||||
| 	*p = x | ||||
| 	return p | ||||
| } | ||||
| func (x EGCSystemMsg) String() string { | ||||
| 	return proto.EnumName(EGCSystemMsg_name, int32(x)) | ||||
| } | ||||
| func (x *EGCSystemMsg) UnmarshalJSON(data []byte) error { | ||||
| 	value, err := proto.UnmarshalJSONEnum(EGCSystemMsg_value, data, "EGCSystemMsg") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*x = EGCSystemMsg(value) | ||||
| 	return nil | ||||
| } | ||||
| func (EGCSystemMsg) EnumDescriptor() ([]byte, []int) { return system_fileDescriptor0, []int{0} } | ||||
|  | ||||
| type ESOMsg int32 | ||||
|  | ||||
| const ( | ||||
| 	ESOMsg_k_ESOMsg_Create                   ESOMsg = 21 | ||||
| 	ESOMsg_k_ESOMsg_Update                   ESOMsg = 22 | ||||
| 	ESOMsg_k_ESOMsg_Destroy                  ESOMsg = 23 | ||||
| 	ESOMsg_k_ESOMsg_CacheSubscribed          ESOMsg = 24 | ||||
| 	ESOMsg_k_ESOMsg_CacheUnsubscribed        ESOMsg = 25 | ||||
| 	ESOMsg_k_ESOMsg_UpdateMultiple           ESOMsg = 26 | ||||
| 	ESOMsg_k_ESOMsg_CacheSubscriptionRefresh ESOMsg = 28 | ||||
| 	ESOMsg_k_ESOMsg_CacheSubscribedUpToDate  ESOMsg = 29 | ||||
| ) | ||||
|  | ||||
| var ESOMsg_name = map[int32]string{ | ||||
| 	21: "k_ESOMsg_Create", | ||||
| 	22: "k_ESOMsg_Update", | ||||
| 	23: "k_ESOMsg_Destroy", | ||||
| 	24: "k_ESOMsg_CacheSubscribed", | ||||
| 	25: "k_ESOMsg_CacheUnsubscribed", | ||||
| 	26: "k_ESOMsg_UpdateMultiple", | ||||
| 	28: "k_ESOMsg_CacheSubscriptionRefresh", | ||||
| 	29: "k_ESOMsg_CacheSubscribedUpToDate", | ||||
| } | ||||
| var ESOMsg_value = map[string]int32{ | ||||
| 	"k_ESOMsg_Create":                   21, | ||||
| 	"k_ESOMsg_Update":                   22, | ||||
| 	"k_ESOMsg_Destroy":                  23, | ||||
| 	"k_ESOMsg_CacheSubscribed":          24, | ||||
| 	"k_ESOMsg_CacheUnsubscribed":        25, | ||||
| 	"k_ESOMsg_UpdateMultiple":           26, | ||||
| 	"k_ESOMsg_CacheSubscriptionRefresh": 28, | ||||
| 	"k_ESOMsg_CacheSubscribedUpToDate":  29, | ||||
| } | ||||
|  | ||||
| func (x ESOMsg) Enum() *ESOMsg { | ||||
| 	p := new(ESOMsg) | ||||
| 	*p = x | ||||
| 	return p | ||||
| } | ||||
| func (x ESOMsg) String() string { | ||||
| 	return proto.EnumName(ESOMsg_name, int32(x)) | ||||
| } | ||||
| func (x *ESOMsg) UnmarshalJSON(data []byte) error { | ||||
| 	value, err := proto.UnmarshalJSONEnum(ESOMsg_value, data, "ESOMsg") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*x = ESOMsg(value) | ||||
| 	return nil | ||||
| } | ||||
| func (ESOMsg) EnumDescriptor() ([]byte, []int) { return system_fileDescriptor0, []int{1} } | ||||
|  | ||||
| type EGCBaseClientMsg int32 | ||||
|  | ||||
| const ( | ||||
| 	EGCBaseClientMsg_k_EMsgGCPingRequest            EGCBaseClientMsg = 3001 | ||||
| 	EGCBaseClientMsg_k_EMsgGCPingResponse           EGCBaseClientMsg = 3002 | ||||
| 	EGCBaseClientMsg_k_EMsgGCClientWelcome          EGCBaseClientMsg = 4004 | ||||
| 	EGCBaseClientMsg_k_EMsgGCServerWelcome          EGCBaseClientMsg = 4005 | ||||
| 	EGCBaseClientMsg_k_EMsgGCClientHello            EGCBaseClientMsg = 4006 | ||||
| 	EGCBaseClientMsg_k_EMsgGCServerHello            EGCBaseClientMsg = 4007 | ||||
| 	EGCBaseClientMsg_k_EMsgGCClientConnectionStatus EGCBaseClientMsg = 4009 | ||||
| 	EGCBaseClientMsg_k_EMsgGCServerConnectionStatus EGCBaseClientMsg = 4010 | ||||
| ) | ||||
|  | ||||
| var EGCBaseClientMsg_name = map[int32]string{ | ||||
| 	3001: "k_EMsgGCPingRequest", | ||||
| 	3002: "k_EMsgGCPingResponse", | ||||
| 	4004: "k_EMsgGCClientWelcome", | ||||
| 	4005: "k_EMsgGCServerWelcome", | ||||
| 	4006: "k_EMsgGCClientHello", | ||||
| 	4007: "k_EMsgGCServerHello", | ||||
| 	4009: "k_EMsgGCClientConnectionStatus", | ||||
| 	4010: "k_EMsgGCServerConnectionStatus", | ||||
| } | ||||
| var EGCBaseClientMsg_value = map[string]int32{ | ||||
| 	"k_EMsgGCPingRequest":            3001, | ||||
| 	"k_EMsgGCPingResponse":           3002, | ||||
| 	"k_EMsgGCClientWelcome":          4004, | ||||
| 	"k_EMsgGCServerWelcome":          4005, | ||||
| 	"k_EMsgGCClientHello":            4006, | ||||
| 	"k_EMsgGCServerHello":            4007, | ||||
| 	"k_EMsgGCClientConnectionStatus": 4009, | ||||
| 	"k_EMsgGCServerConnectionStatus": 4010, | ||||
| } | ||||
|  | ||||
| func (x EGCBaseClientMsg) Enum() *EGCBaseClientMsg { | ||||
| 	p := new(EGCBaseClientMsg) | ||||
| 	*p = x | ||||
| 	return p | ||||
| } | ||||
| func (x EGCBaseClientMsg) String() string { | ||||
| 	return proto.EnumName(EGCBaseClientMsg_name, int32(x)) | ||||
| } | ||||
| func (x *EGCBaseClientMsg) UnmarshalJSON(data []byte) error { | ||||
| 	value, err := proto.UnmarshalJSONEnum(EGCBaseClientMsg_value, data, "EGCBaseClientMsg") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*x = EGCBaseClientMsg(value) | ||||
| 	return nil | ||||
| } | ||||
| func (EGCBaseClientMsg) EnumDescriptor() ([]byte, []int) { return system_fileDescriptor0, []int{2} } | ||||
|  | ||||
| type EGCToGCMsg int32 | ||||
|  | ||||
| const ( | ||||
| 	EGCToGCMsg_k_EGCToGCMsgMasterAck                   EGCToGCMsg = 150 | ||||
| 	EGCToGCMsg_k_EGCToGCMsgMasterAckResponse           EGCToGCMsg = 151 | ||||
| 	EGCToGCMsg_k_EGCToGCMsgRouted                      EGCToGCMsg = 152 | ||||
| 	EGCToGCMsg_k_EGCToGCMsgRoutedReply                 EGCToGCMsg = 153 | ||||
| 	EGCToGCMsg_k_EMsgGCUpdateSubGCSessionInfo          EGCToGCMsg = 154 | ||||
| 	EGCToGCMsg_k_EMsgGCRequestSubGCSessionInfo         EGCToGCMsg = 155 | ||||
| 	EGCToGCMsg_k_EMsgGCRequestSubGCSessionInfoResponse EGCToGCMsg = 156 | ||||
| 	EGCToGCMsg_k_EGCToGCMsgMasterStartupComplete       EGCToGCMsg = 157 | ||||
| 	EGCToGCMsg_k_EMsgGCToGCSOCacheSubscribe            EGCToGCMsg = 158 | ||||
| 	EGCToGCMsg_k_EMsgGCToGCSOCacheUnsubscribe          EGCToGCMsg = 159 | ||||
| 	EGCToGCMsg_k_EMsgGCToGCLoadSessionSOCache          EGCToGCMsg = 160 | ||||
| 	EGCToGCMsg_k_EMsgGCToGCLoadSessionSOCacheResponse  EGCToGCMsg = 161 | ||||
| 	EGCToGCMsg_k_EMsgGCToGCUpdateSessionStats          EGCToGCMsg = 162 | ||||
| ) | ||||
|  | ||||
| var EGCToGCMsg_name = map[int32]string{ | ||||
| 	150: "k_EGCToGCMsgMasterAck", | ||||
| 	151: "k_EGCToGCMsgMasterAckResponse", | ||||
| 	152: "k_EGCToGCMsgRouted", | ||||
| 	153: "k_EGCToGCMsgRoutedReply", | ||||
| 	154: "k_EMsgGCUpdateSubGCSessionInfo", | ||||
| 	155: "k_EMsgGCRequestSubGCSessionInfo", | ||||
| 	156: "k_EMsgGCRequestSubGCSessionInfoResponse", | ||||
| 	157: "k_EGCToGCMsgMasterStartupComplete", | ||||
| 	158: "k_EMsgGCToGCSOCacheSubscribe", | ||||
| 	159: "k_EMsgGCToGCSOCacheUnsubscribe", | ||||
| 	160: "k_EMsgGCToGCLoadSessionSOCache", | ||||
| 	161: "k_EMsgGCToGCLoadSessionSOCacheResponse", | ||||
| 	162: "k_EMsgGCToGCUpdateSessionStats", | ||||
| } | ||||
| var EGCToGCMsg_value = map[string]int32{ | ||||
| 	"k_EGCToGCMsgMasterAck":                   150, | ||||
| 	"k_EGCToGCMsgMasterAckResponse":           151, | ||||
| 	"k_EGCToGCMsgRouted":                      152, | ||||
| 	"k_EGCToGCMsgRoutedReply":                 153, | ||||
| 	"k_EMsgGCUpdateSubGCSessionInfo":          154, | ||||
| 	"k_EMsgGCRequestSubGCSessionInfo":         155, | ||||
| 	"k_EMsgGCRequestSubGCSessionInfoResponse": 156, | ||||
| 	"k_EGCToGCMsgMasterStartupComplete":       157, | ||||
| 	"k_EMsgGCToGCSOCacheSubscribe":            158, | ||||
| 	"k_EMsgGCToGCSOCacheUnsubscribe":          159, | ||||
| 	"k_EMsgGCToGCLoadSessionSOCache":          160, | ||||
| 	"k_EMsgGCToGCLoadSessionSOCacheResponse":  161, | ||||
| 	"k_EMsgGCToGCUpdateSessionStats":          162, | ||||
| } | ||||
|  | ||||
| func (x EGCToGCMsg) Enum() *EGCToGCMsg { | ||||
| 	p := new(EGCToGCMsg) | ||||
| 	*p = x | ||||
| 	return p | ||||
| } | ||||
| func (x EGCToGCMsg) String() string { | ||||
| 	return proto.EnumName(EGCToGCMsg_name, int32(x)) | ||||
| } | ||||
| func (x *EGCToGCMsg) UnmarshalJSON(data []byte) error { | ||||
| 	value, err := proto.UnmarshalJSONEnum(EGCToGCMsg_value, data, "EGCToGCMsg") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*x = EGCToGCMsg(value) | ||||
| 	return nil | ||||
| } | ||||
| func (EGCToGCMsg) EnumDescriptor() ([]byte, []int) { return system_fileDescriptor0, []int{3} } | ||||
|  | ||||
| func init() { | ||||
| 	proto.RegisterEnum("EGCSystemMsg", EGCSystemMsg_name, EGCSystemMsg_value) | ||||
| 	proto.RegisterEnum("ESOMsg", ESOMsg_name, ESOMsg_value) | ||||
| 	proto.RegisterEnum("EGCBaseClientMsg", EGCBaseClientMsg_name, EGCBaseClientMsg_value) | ||||
| 	proto.RegisterEnum("EGCToGCMsg", EGCToGCMsg_name, EGCToGCMsg_value) | ||||
| } | ||||
|  | ||||
| var system_fileDescriptor0 = []byte{ | ||||
| 	// 1475 bytes of a gzipped FileDescriptorProto | ||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x57, 0x59, 0x73, 0x1b, 0xc5, | ||||
| 	0x13, 0xcf, 0x96, 0xfc, 0xff, 0x3f, 0x4c, 0x41, 0xd1, 0x99, 0xc4, 0x47, 0x12, 0x27, 0x4a, 0x42, | ||||
| 	0x0e, 0x62, 0xa8, 0x3c, 0x84, 0xfb, 0x46, 0x91, 0x64, 0x5b, 0x41, 0x8e, 0x15, 0x4b, 0xb6, 0xb9, | ||||
| 	0xcd, 0x7a, 0x35, 0xb6, 0xb6, 0x2c, 0xed, 0x2c, 0x33, 0xbb, 0x26, 0x7e, 0x0b, 0xd7, 0x57, 0xe0, | ||||
| 	0xbe, 0x8b, 0xa3, 0xe0, 0x1b, 0xc0, 0x27, 0xe0, 0x7c, 0x81, 0x57, 0xee, 0x7c, 0x01, 0x1e, 0xb8, | ||||
| 	0x21, 0x55, 0xf4, 0xee, 0xce, 0xce, 0xce, 0x4a, 0xb2, 0x79, 0x93, 0xe6, 0xd7, 0xdd, 0xd3, 0xdd, | ||||
| 	0xd3, 0xfd, 0xeb, 0x5e, 0x42, 0xd7, 0x1d, 0xb9, 0x25, 0x03, 0xd6, 0xeb, 0xc9, 0x75, 0x79, 0xda, | ||||
| 	0x17, 0x3c, 0xe0, 0x53, 0x97, 0x47, 0xc9, 0x55, 0xd5, 0x99, 0x72, 0x33, 0x3e, 0x9f, 0x93, 0xeb, | ||||
| 	0x74, 0x0f, 0xb9, 0x66, 0x63, 0x05, 0x4f, 0xf0, 0x77, 0xcd, 0xdb, 0xb4, 0xbb, 0x6e, 0x1b, 0x76, | ||||
| 	0xd1, 0xdd, 0xe4, 0xea, 0xf4, 0x70, 0x2e, 0xec, 0x06, 0x2e, 0x58, 0x74, 0x82, 0xec, 0x4d, 0x8f, | ||||
| 	0x66, 0x98, 0xc7, 0x84, 0xeb, 0x2c, 0x30, 0xbf, 0xbb, 0x05, 0x84, 0x8e, 0x11, 0x9a, 0x22, 0x89, | ||||
| 	0xd9, 0xb3, 0xb6, 0x64, 0x70, 0x86, 0x1e, 0x22, 0xfb, 0xd3, 0xf3, 0x92, 0xd3, 0x71, 0xd9, 0x26, | ||||
| 	0xeb, 0x31, 0x2f, 0x28, 0x3d, 0x69, 0x8b, 0x36, 0x6b, 0xc3, 0x8d, 0xa6, 0x5e, 0x99, 0x7b, 0x65, | ||||
| 	0xde, 0xeb, 0xd9, 0x5e, 0x1b, 0x6e, 0x32, 0x6f, 0x6a, 0x06, 0xb6, 0x08, 0x1a, 0x5d, 0x7b, 0xcb, | ||||
| 	0xf5, 0xd6, 0xe1, 0x66, 0x3a, 0x4e, 0xf6, 0x64, 0x08, 0xf7, 0x53, 0xe0, 0x16, 0x7a, 0x80, 0x8c, | ||||
| 	0xe7, 0x54, 0x66, 0xec, 0x1e, 0x93, 0x4c, 0x6c, 0x32, 0x01, 0xb7, 0xd2, 0xfd, 0x64, 0xcc, 0xd4, | ||||
| 	0x32, 0xb0, 0xdb, 0xe8, 0x28, 0xd9, 0x9d, 0x62, 0xcb, 0x33, 0x0b, 0xec, 0x89, 0x90, 0xc9, 0x00, | ||||
| 	0x6e, 0x37, 0x5d, 0x8b, 0x8e, 0xa5, 0xcf, 0x3d, 0x0c, 0xe9, 0x0e, 0x7a, 0x94, 0x1c, 0xca, 0x92, | ||||
| 	0x10, 0x2c, 0xa2, 0x99, 0xc8, 0x1a, 0x5e, 0x19, 0xc8, 0xa6, 0xd3, 0x61, 0x3d, 0x1b, 0xee, 0xa4, | ||||
| 	0x53, 0xe4, 0xc4, 0xce, 0x32, 0xda, 0xde, 0x5d, 0x43, 0xec, 0xc5, 0x72, 0x95, 0x6a, 0x63, 0xa1, | ||||
| 	0x5a, 0x2e, 0xb5, 0xaa, 0x15, 0xb8, 0x9b, 0x1e, 0x26, 0x93, 0xc3, 0x64, 0xb4, 0x95, 0x7b, 0xcc, | ||||
| 	0x00, 0x4b, 0xbe, 0x5f, 0xf3, 0xd6, 0xf8, 0xa2, 0xdf, 0xb6, 0x03, 0x4c, 0xf2, 0xbd, 0x66, 0x66, | ||||
| 	0x96, 0xa2, 0xc7, 0xc5, 0xe3, 0x26, 0x93, 0xd2, 0xe5, 0x1e, 0xdc, 0x47, 0xaf, 0x25, 0xc5, 0x6d, | ||||
| 	0x40, 0x6d, 0xbd, 0x64, 0xfa, 0x58, 0xe7, 0x7c, 0x23, 0xf4, 0x4b, 0x8e, 0xc3, 0x43, 0x2f, 0x98, | ||||
| 	0x16, 0xbc, 0x57, 0xf3, 0xfc, 0x30, 0x80, 0xb3, 0xb9, 0xfc, 0x33, 0xaf, 0x3d, 0xdb, 0x6a, 0x35, | ||||
| 	0xd2, 0x64, 0x96, 0xcd, 0x5b, 0xfa, 0x40, 0x7d, 0x4b, 0xc5, 0x7c, 0xf4, 0x86, 0x60, 0x2d, 0x04, | ||||
| 	0x9b, 0x2c, 0x08, 0x7d, 0xa8, 0xd2, 0x22, 0x39, 0x90, 0x22, 0x0b, 0xcc, 0xe1, 0xa2, 0xdd, 0x0c, | ||||
| 	0x7d, 0x9f, 0x8b, 0xa0, 0xe4, 0x04, 0x51, 0x14, 0xd3, 0xf4, 0x3a, 0x72, 0xcc, 0x48, 0x90, 0xf2, | ||||
| 	0xae, 0xc2, 0x02, 0xdb, 0xed, 0xca, 0x15, 0x23, 0x95, 0x33, 0x66, 0x28, 0x68, 0x8a, 0xb9, 0x9b, | ||||
| 	0xac, 0xe6, 0x05, 0x4c, 0x60, 0xd2, 0xe6, 0x30, 0x6c, 0x7b, 0x9d, 0x41, 0xcd, 0x74, 0x64, 0xda, | ||||
| 	0xf5, 0xda, 0xca, 0x9c, 0x84, 0x73, 0x66, 0xad, 0x34, 0xb8, 0x0c, 0x4a, 0x5d, 0x26, 0x02, 0xb8, | ||||
| 	0xdf, 0x2c, 0x4a, 0xbc, 0xbe, 0xee, 0x3a, 0x0c, 0x23, 0x92, 0x50, 0xcf, 0x77, 0x4c, 0xf6, 0x70, | ||||
| 	0x30, 0xd7, 0xa7, 0xa2, 0x2a, 0x5f, 0xc2, 0x79, 0x33, 0x56, 0x03, 0xd0, 0x69, 0x9a, 0xcf, 0x3d, | ||||
| 	0x75, 0xbb, 0x3d, 0x2d, 0x18, 0x53, 0x17, 0x42, 0xc3, 0x8c, 0x2e, 0x8f, 0x69, 0xfd, 0x0b, 0x74, | ||||
| 	0x1f, 0x19, 0x35, 0x2e, 0xa8, 0x35, 0xea, 0xdc, 0xb1, 0xe3, 0x34, 0x2e, 0xd0, 0x23, 0xe4, 0xe0, | ||||
| 	0x50, 0x48, 0x6b, 0x37, 0xe9, 0x41, 0xb2, 0x2f, 0xdf, 0xe9, 0x66, 0xe5, 0xb7, 0x4c, 0xe7, 0xd0, | ||||
| 	0x82, 0x21, 0x01, 0x8b, 0x7d, 0x95, 0x6e, 0x60, 0xda, 0xfc, 0x92, 0x99, 0xe0, 0xa8, 0x50, 0xaa, | ||||
| 	0x3d, 0x7c, 0x41, 0x58, 0xce, 0xdd, 0x9a, 0x1e, 0x6b, 0xad, 0x07, 0xe8, 0x24, 0x99, 0x30, 0x2c, | ||||
| 	0xc7, 0x68, 0x8b, 0xf5, 0xfc, 0x2e, 0x16, 0x33, 0x3c, 0x48, 0x8f, 0x91, 0xc3, 0xdb, 0xa1, 0xda, | ||||
| 	0xc6, 0x43, 0x39, 0xcf, 0x85, 0xed, 0x05, 0x33, 0x51, 0x75, 0x36, 0x6c, 0x29, 0xe1, 0xe1, 0x9c, | ||||
| 	0xe7, 0x39, 0x4c, 0xeb, 0x3f, 0x62, 0xba, 0x38, 0x50, 0x82, 0xf0, 0x28, 0x3d, 0x4e, 0x8e, 0x6c, | ||||
| 	0x0b, 0x6b, 0x2b, 0x8f, 0x99, 0x5d, 0x84, 0x62, 0x0d, 0x26, 0x24, 0xf7, 0xec, 0xf3, 0x11, 0x5d, | ||||
| 	0xc1, 0x8a, 0xd9, 0x45, 0x7d, 0xa0, 0xb6, 0xf0, 0xb8, 0x59, 0x72, 0x31, 0x6f, 0xfb, 0x5d, 0x76, | ||||
| 	0x11, 0x7f, 0x83, 0x6d, 0xe6, 0x61, 0x99, 0xad, 0x96, 0x1a, 0xb5, 0x05, 0xb6, 0xee, 0xe2, 0x23, | ||||
| 	0x88, 0xb8, 0x03, 0xd6, 0x6c, 0x07, 0x2f, 0x61, 0x66, 0x2e, 0x13, 0xa9, 0x73, 0x7c, 0x35, 0x6d, | ||||
| 	0xe4, 0x35, 0xb3, 0xd1, 0xfa, 0xd1, 0xd9, 0x20, 0xf0, 0xb5, 0x1f, 0x1d, 0x7a, 0x3d, 0x39, 0xb9, | ||||
| 	0x9d, 0xe4, 0x34, 0x17, 0xd1, 0x04, 0xd0, 0xc2, 0x2e, 0xd6, 0x64, 0xe6, 0x34, 0xeb, 0x95, 0x6d, | ||||
| 	0x2c, 0xa7, 0x36, 0x86, 0x08, 0x9f, 0x58, 0x58, 0x93, 0x93, 0xc3, 0x20, 0xad, 0xfc, 0xa9, 0x35, | ||||
| 	0x54, 0x1b, 0xa9, 0x03, 0x3e, 0xb3, 0x30, 0x9a, 0xf1, 0x01, 0xa8, 0xc2, 0xba, 0x0c, 0x0b, 0xe3, | ||||
| 	0x73, 0x0b, 0xb3, 0x3d, 0x36, 0xa8, 0x18, 0x57, 0xeb, 0x17, 0x16, 0x66, 0xfb, 0xd0, 0x70, 0x50, | ||||
| 	0x5f, 0xfd, 0xa5, 0x85, 0xf5, 0x0a, 0xba, 0x30, 0x2f, 0xd4, 0x13, 0xdd, 0xaf, 0x2c, 0x2c, 0x86, | ||||
| 	0x89, 0xfe, 0x63, 0xad, 0xf5, 0xb5, 0x85, 0x3d, 0xae, 0xc7, 0xe2, 0x9c, 0x1d, 0xbd, 0x00, 0x7a, | ||||
| 	0x5b, 0x71, 0x05, 0x73, 0x02, 0x2e, 0xb6, 0xe0, 0x1b, 0x8b, 0x9e, 0x24, 0x47, 0xb7, 0x17, 0xd0, | ||||
| 	0x96, 0xbe, 0xcd, 0x3b, 0x99, 0x0a, 0xaa, 0xc7, 0xe5, 0x61, 0x10, 0x4d, 0xc6, 0xef, 0x2c, 0x7c, | ||||
| 	0x8a, 0x13, 0x3b, 0x0b, 0x69, 0x8b, 0xdf, 0x5b, 0xf4, 0x44, 0x56, 0xa8, 0x5a, 0xb8, 0xdc, 0x75, | ||||
| 	0x71, 0x6c, 0x47, 0x94, 0xa9, 0x8c, 0xfe, 0x60, 0xd1, 0xd3, 0xe4, 0xd4, 0x7f, 0xca, 0x69, 0xbb, | ||||
| 	0x3f, 0x5a, 0x48, 0x78, 0xd9, 0x8a, 0xc0, 0x82, 0x79, 0x3f, 0xe2, 0x15, 0x09, 0x3f, 0xe5, 0x92, | ||||
| 	0x91, 0x01, 0x5a, 0xf3, 0x72, 0xb4, 0x76, 0xec, 0x19, 0x5c, 0x2e, 0xce, 0xc0, 0x2f, 0x05, 0x33, | ||||
| 	0xfa, 0xa8, 0x21, 0x42, 0xe1, 0x74, 0x10, 0x6a, 0x89, 0x10, 0x47, 0x07, 0xe6, 0x3c, 0x94, 0xf0, | ||||
| 	0x6b, 0xc1, 0x8c, 0x7e, 0xb8, 0x90, 0xbe, 0xeb, 0xb7, 0x02, 0xb2, 0x80, 0x26, 0xc7, 0x64, 0x80, | ||||
| 	0xa6, 0x93, 0xf2, 0xf7, 0x02, 0xb6, 0x70, 0xc6, 0x23, 0x65, 0xd5, 0xc1, 0x4b, 0xb6, 0x93, 0x18, | ||||
| 	0x29, 0x77, 0x6c, 0x0f, 0x87, 0xc7, 0x1f, 0x05, 0xb3, 0xe4, 0xca, 0x1d, 0xe6, 0x6c, 0x4c, 0x0b, | ||||
| 	0x4c, 0x4a, 0x5b, 0x76, 0x5c, 0x1f, 0xfe, 0x2c, 0x60, 0x13, 0x16, 0xb7, 0x41, 0xb5, 0x1b, 0x7f, | ||||
| 	0x15, 0x90, 0x70, 0x4c, 0x22, 0x6e, 0xe0, 0x3a, 0x83, 0xeb, 0x96, 0xba, 0xb2, 0xee, 0x7a, 0x1b, | ||||
| 	0xf0, 0x77, 0x01, 0x97, 0x8c, 0xe3, 0x3b, 0xca, 0x68, 0x7b, 0xff, 0x14, 0xe8, 0xa9, 0xac, 0x6d, | ||||
| 	0x97, 0x9a, 0xb8, 0xb4, 0xe1, 0xec, 0xc4, 0x62, 0x0e, 0xa5, 0xef, 0x3a, 0x2e, 0x0f, 0x65, 0x34, | ||||
| 	0x47, 0x37, 0xdd, 0x60, 0x0b, 0xae, 0x14, 0xcc, 0xe7, 0xa8, 0x34, 0x94, 0xd5, 0x39, 0xd7, 0x11, | ||||
| 	0xbc, 0x75, 0x11, 0xdf, 0xeb, 0xd2, 0x88, 0x59, 0x9b, 0x83, 0x02, 0xfa, 0xd2, 0xa7, 0x46, 0xcc, | ||||
| 	0xde, 0x88, 0xa7, 0x49, 0xa9, 0x79, 0x1e, 0x9e, 0x1e, 0x31, 0x7b, 0x23, 0x3d, 0xd6, 0x5a, 0xcf, | ||||
| 	0x8c, 0xe0, 0xca, 0x98, 0xe3, 0x51, 0xdf, 0x57, 0x19, 0xaa, 0x23, 0x55, 0xc1, 0xb3, 0x23, 0x66, | ||||
| 	0x7d, 0x0e, 0xe0, 0xda, 0xce, 0x73, 0x23, 0x53, 0x3f, 0x5b, 0xe4, 0xff, 0xd5, 0xe6, 0x7c, 0xb6, | ||||
| 	0xdf, 0xc6, 0xbf, 0x57, 0xca, 0x82, 0x45, 0x53, 0x61, 0x34, 0x77, 0x98, 0x3c, 0x35, 0x8c, 0xd1, | ||||
| 	0xbd, 0xb1, 0xcb, 0xc9, 0x61, 0x05, 0x99, 0x4a, 0xf0, 0x2d, 0x18, 0x57, 0x94, 0xa8, 0xf4, 0x23, | ||||
| 	0x1e, 0x68, 0x86, 0xab, 0xd2, 0x11, 0xee, 0x2a, 0xae, 0x57, 0x13, 0x6a, 0xc7, 0x35, 0xd0, 0x45, | ||||
| 	0x4f, 0x66, 0xf8, 0x3e, 0x45, 0xe9, 0xe6, 0x45, 0x29, 0x2f, 0xc3, 0x7e, 0x35, 0x16, 0x06, 0x4d, | ||||
| 	0xfb, 0xc9, 0xd8, 0x5d, 0x13, 0x4c, 0x76, 0x60, 0x52, 0x51, 0xf7, 0x50, 0x0f, 0x16, 0xfd, 0x16, | ||||
| 	0xaf, 0x44, 0xde, 0x1f, 0x9c, 0xba, 0x62, 0x11, 0xc0, 0xcc, 0x44, 0xed, 0xa1, 0x3b, 0x51, 0x75, | ||||
| 	0x4f, 0x5c, 0xb3, 0x8d, 0xb8, 0x25, 0x13, 0x2a, 0xff, 0x68, 0x5c, 0xd1, 0xa6, 0x81, 0xa8, 0xe4, | ||||
| 	0x7d, 0x3c, 0xae, 0xda, 0x20, 0x86, 0x12, 0x4b, 0xcb, 0xac, 0xeb, 0xf0, 0x1e, 0x83, 0x77, 0x8a, | ||||
| 	0x26, 0xd6, 0x8c, 0x77, 0xe8, 0x14, 0x7b, 0xb7, 0x68, 0x5e, 0x96, 0xe8, 0xcd, 0xb2, 0x6e, 0x97, | ||||
| 	0xc3, 0x7b, 0x39, 0x24, 0xd1, 0x4a, 0x90, 0xf7, 0x8b, 0xaa, 0x89, 0x0d, 0x1d, 0xfc, 0x12, 0xf0, | ||||
| 	0x58, 0xbc, 0xd9, 0xa9, 0x26, 0xfe, 0x20, 0x27, 0x94, 0xa8, 0x0f, 0x08, 0x7d, 0x58, 0x9c, 0xba, | ||||
| 	0x5c, 0x20, 0x04, 0xe3, 0x6f, 0xf1, 0xb8, 0x3a, 0x74, 0x2f, 0xab, 0xff, 0x09, 0x4b, 0x95, 0x9c, | ||||
| 	0x0d, 0x78, 0xde, 0xd2, 0x0d, 0xd6, 0x8f, 0xe9, 0x24, 0xbc, 0x90, 0x31, 0x96, 0x92, 0x89, 0x38, | ||||
| 	0x0d, 0x1f, 0xf4, 0xc5, 0x6c, 0xa8, 0xe4, 0x80, 0xe4, 0x53, 0xe8, 0x25, 0xcb, 0x74, 0x55, 0x51, | ||||
| 	0x48, 0xb8, 0x1a, 0x79, 0x1d, 0xf3, 0x48, 0xb4, 0x99, 0xc3, 0xcb, 0x96, 0xa2, 0x81, 0x58, 0x48, | ||||
| 	0xbd, 0xc8, 0x80, 0xd4, 0x2b, 0x16, 0xbd, 0x21, 0x9e, 0xa1, 0x3b, 0x49, 0x69, 0x7f, 0x5f, 0xcd, | ||||
| 	0x98, 0x3b, 0x17, 0x53, 0xfc, 0x2d, 0x14, 0xfa, 0xb8, 0x47, 0xfa, 0xf1, 0xd4, 0x7b, 0x2d, 0x9d, | ||||
| 	0xa8, 0xb1, 0xd5, 0x48, 0xb4, 0x39, 0x9f, 0xaf, 0x28, 0x78, 0x3d, 0x17, 0x83, 0x21, 0x62, 0x14, | ||||
| 	0x36, 0xbc, 0x31, 0x20, 0x54, 0xe7, 0x76, 0x5b, 0x79, 0xa6, 0xe4, 0xe1, 0xcd, 0x74, 0xf6, 0xec, | ||||
| 	0x20, 0xa4, 0x23, 0x78, 0x6b, 0xc0, 0x62, 0x8e, 0x81, 0x93, 0xd9, 0xfa, 0xb6, 0x75, 0xf6, 0x7f, | ||||
| 	0xb3, 0xd6, 0x25, 0x6b, 0xd7, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x05, 0xab, 0xaf, 0x14, 0xda, | ||||
| 	0x0e, 0x00, 0x00, | ||||
| } | ||||
							
								
								
									
										188
									
								
								vendor/github.com/Philipp15b/go-steam/economy/inventory/inventory.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										188
									
								
								vendor/github.com/Philipp15b/go-steam/economy/inventory/inventory.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,188 +0,0 @@ | ||||
| /* | ||||
| Includes inventory types as used in the trade package | ||||
| */ | ||||
| package inventory | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"github.com/Philipp15b/go-steam/jsont" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| type GenericInventory map[uint32]map[uint64]*Inventory | ||||
|  | ||||
| func NewGenericInventory() GenericInventory { | ||||
| 	iMap := make(map[uint32]map[uint64]*Inventory) | ||||
| 	return GenericInventory(iMap) | ||||
| } | ||||
|  | ||||
| // Get inventory for specified AppId and ContextId | ||||
| func (i *GenericInventory) Get(appId uint32, contextId uint64) (*Inventory, error) { | ||||
| 	iMap := (map[uint32]map[uint64]*Inventory)(*i) | ||||
| 	iMap2, ok := iMap[appId] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("inventory for specified appId not found") | ||||
| 	} | ||||
| 	inv, ok := iMap2[contextId] | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("inventory for specified contextId not found") | ||||
| 	} | ||||
| 	return inv, nil | ||||
| } | ||||
|  | ||||
| func (i *GenericInventory) Add(appId uint32, contextId uint64, inv *Inventory) { | ||||
| 	iMap := (map[uint32]map[uint64]*Inventory)(*i) | ||||
| 	iMap2, ok := iMap[appId] | ||||
| 	if !ok { | ||||
| 		iMap2 = make(map[uint64]*Inventory) | ||||
| 		iMap[appId] = iMap2 | ||||
| 	} | ||||
| 	iMap2[contextId] = inv | ||||
| } | ||||
|  | ||||
| type Inventory struct { | ||||
| 	Items        Items        `json:"rgInventory"` | ||||
| 	Currencies   Currencies   `json:"rgCurrency"` | ||||
| 	Descriptions Descriptions `json:"rgDescriptions"` | ||||
| 	AppInfo      *AppInfo     `json:"rgAppInfo"` | ||||
| } | ||||
|  | ||||
| // Items key is an AssetId | ||||
| type Items map[string]*Item | ||||
|  | ||||
| func (i *Items) ToMap() map[string]*Item { | ||||
| 	return (map[string]*Item)(*i) | ||||
| } | ||||
|  | ||||
| func (i *Items) Get(assetId uint64) (*Item, error) { | ||||
| 	iMap := (map[string]*Item)(*i) | ||||
| 	if item, ok := iMap[strconv.FormatUint(assetId, 10)]; ok { | ||||
| 		return item, nil | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("item not found") | ||||
| } | ||||
|  | ||||
| func (i *Items) UnmarshalJSON(data []byte) error { | ||||
| 	if bytes.Equal(data, []byte("[]")) { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return json.Unmarshal(data, (*map[string]*Item)(i)) | ||||
| } | ||||
|  | ||||
| type Currencies map[string]*Currency | ||||
|  | ||||
| func (c *Currencies) ToMap() map[string]*Currency { | ||||
| 	return (map[string]*Currency)(*c) | ||||
| } | ||||
|  | ||||
| func (c *Currencies) UnmarshalJSON(data []byte) error { | ||||
| 	if bytes.Equal(data, []byte("[]")) { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return json.Unmarshal(data, (*map[string]*Currency)(c)) | ||||
| } | ||||
|  | ||||
| // Descriptions key format is %d_%d, first %d is ClassId, second is InstanceId | ||||
| type Descriptions map[string]*Description | ||||
|  | ||||
| func (d *Descriptions) ToMap() map[string]*Description { | ||||
| 	return (map[string]*Description)(*d) | ||||
| } | ||||
|  | ||||
| func (d *Descriptions) Get(classId uint64, instanceId uint64) (*Description, error) { | ||||
| 	dMap := (map[string]*Description)(*d) | ||||
| 	descId := fmt.Sprintf("%v_%v", classId, instanceId) | ||||
| 	if desc, ok := dMap[descId]; ok { | ||||
| 		return desc, nil | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("description not found") | ||||
| } | ||||
|  | ||||
| func (d *Descriptions) UnmarshalJSON(data []byte) error { | ||||
| 	if bytes.Equal(data, []byte("[]")) { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return json.Unmarshal(data, (*map[string]*Description)(d)) | ||||
| } | ||||
|  | ||||
| type Item struct { | ||||
| 	Id         uint64 `json:",string"` | ||||
| 	ClassId    uint64 `json:",string"` | ||||
| 	InstanceId uint64 `json:",string"` | ||||
| 	Amount     uint64 `json:",string"` | ||||
| 	Pos        uint32 | ||||
| } | ||||
|  | ||||
| type Currency struct { | ||||
| 	Id         uint64 `json:",string"` | ||||
| 	ClassId    uint64 `json:",string"` | ||||
| 	IsCurrency bool   `json:"is_currency"` | ||||
| 	Pos        uint32 | ||||
| } | ||||
|  | ||||
| type Description struct { | ||||
| 	AppId      uint32 `json:",string"` | ||||
| 	ClassId    uint64 `json:",string"` | ||||
| 	InstanceId uint64 `json:",string"` | ||||
|  | ||||
| 	IconUrl      string `json:"icon_url"` | ||||
| 	IconUrlLarge string `json:"icon_url_large"` | ||||
| 	IconDragUrl  string `json:"icon_drag_url"` | ||||
|  | ||||
| 	Name           string | ||||
| 	MarketName     string `json:"market_name"` | ||||
| 	MarketHashName string `json:"market_hash_name"` | ||||
|  | ||||
| 	// Colors in hex, for example `B2B2B2` | ||||
| 	NameColor       string `json:"name_color"` | ||||
| 	BackgroundColor string `json:"background_color"` | ||||
|  | ||||
| 	Type string | ||||
|  | ||||
| 	Tradable                  jsont.UintBool | ||||
| 	Marketable                jsont.UintBool | ||||
| 	Commodity                 jsont.UintBool | ||||
| 	MarketTradableRestriction uint32 `json:"market_tradable_restriction,string"` | ||||
|  | ||||
| 	Descriptions DescriptionLines | ||||
| 	Actions      []*Action | ||||
| 	// Application-specific data, like "def_index" and "quality" for TF2 | ||||
| 	AppData map[string]string | ||||
| 	Tags    []*Tag | ||||
| } | ||||
|  | ||||
| type DescriptionLines []*DescriptionLine | ||||
|  | ||||
| func (d *DescriptionLines) UnmarshalJSON(data []byte) error { | ||||
| 	if bytes.Equal(data, []byte(`""`)) { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return json.Unmarshal(data, (*[]*DescriptionLine)(d)) | ||||
| } | ||||
|  | ||||
| type DescriptionLine struct { | ||||
| 	Value string | ||||
| 	Type  *string // Is `html` for HTML descriptions | ||||
| 	Color *string | ||||
| } | ||||
|  | ||||
| type Action struct { | ||||
| 	Name string | ||||
| 	Link string | ||||
| } | ||||
|  | ||||
| type AppInfo struct { | ||||
| 	AppId uint32 | ||||
| 	Name  string | ||||
| 	Icon  string | ||||
| 	Link  string | ||||
| } | ||||
|  | ||||
| type Tag struct { | ||||
| 	InternalName string `json:internal_name` | ||||
| 	Name         string | ||||
| 	Category     string | ||||
| 	CategoryName string `json:category_name` | ||||
| } | ||||
							
								
								
									
										79
									
								
								vendor/github.com/Philipp15b/go-steam/economy/inventory/inventory_apps.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										79
									
								
								vendor/github.com/Philipp15b/go-steam/economy/inventory/inventory_apps.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,79 +0,0 @@ | ||||
| package inventory | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"github.com/Philipp15b/go-steam/steamid" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| type InventoryApps map[string]*InventoryApp | ||||
|  | ||||
| func (i *InventoryApps) Get(appId uint32) (*InventoryApp, error) { | ||||
| 	iMap := (map[string]*InventoryApp)(*i) | ||||
| 	if inventoryApp, ok := iMap[strconv.FormatUint(uint64(appId), 10)]; ok { | ||||
| 		return inventoryApp, nil | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("inventory app not found") | ||||
| } | ||||
|  | ||||
| func (i *InventoryApps) ToMap() map[string]*InventoryApp { | ||||
| 	return (map[string]*InventoryApp)(*i) | ||||
| } | ||||
|  | ||||
| type InventoryApp struct { | ||||
| 	AppId            uint32 | ||||
| 	Name             string | ||||
| 	Icon             string | ||||
| 	Link             string | ||||
| 	AssetCount       uint32   `json:"asset_count"` | ||||
| 	InventoryLogo    string   `json:"inventory_logo"` | ||||
| 	TradePermissions string   `json:"trade_permissions"` | ||||
| 	Contexts         Contexts `json:"rgContexts"` | ||||
| } | ||||
|  | ||||
| type Contexts map[string]*Context | ||||
|  | ||||
| func (c *Contexts) Get(contextId uint64) (*Context, error) { | ||||
| 	cMap := (map[string]*Context)(*c) | ||||
| 	if context, ok := cMap[strconv.FormatUint(contextId, 10)]; ok { | ||||
| 		return context, nil | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("context not found") | ||||
| } | ||||
|  | ||||
| func (c *Contexts) ToMap() map[string]*Context { | ||||
| 	return (map[string]*Context)(*c) | ||||
| } | ||||
|  | ||||
| type Context struct { | ||||
| 	ContextId  uint64 `json:"id,string"` | ||||
| 	AssetCount uint32 `json:"asset_count"` | ||||
| 	Name       string | ||||
| } | ||||
|  | ||||
| func GetInventoryApps(client *http.Client, steamId steamid.SteamId) (InventoryApps, error) { | ||||
| 	resp, err := http.Get("http://steamcommunity.com/profiles/" + steamId.ToString() + "/inventory/") | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	respBody, err := ioutil.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	reg := regexp.MustCompile("var g_rgAppContextData = (.*?);") | ||||
| 	inventoryAppsMatches := reg.FindSubmatch(respBody) | ||||
| 	if inventoryAppsMatches == nil { | ||||
| 		return nil, fmt.Errorf("profile inventory not found in steam response") | ||||
| 	} | ||||
| 	var inventoryApps InventoryApps | ||||
| 	if err = json.Unmarshal(inventoryAppsMatches[1], &inventoryApps); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return inventoryApps, nil | ||||
| } | ||||
							
								
								
									
										28
									
								
								vendor/github.com/Philipp15b/go-steam/economy/inventory/own.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/Philipp15b/go-steam/economy/inventory/own.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,28 +0,0 @@ | ||||
| package inventory | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| func GetPartialOwnInventory(client *http.Client, contextId uint64, appId uint32, start *uint) (*PartialInventory, error) { | ||||
| 	// TODO: the "trading" parameter can be left off to return non-tradable items too | ||||
| 	url := fmt.Sprintf("http://steamcommunity.com/my/inventory/json/%d/%d?trading=1", appId, contextId) | ||||
| 	if start != nil { | ||||
| 		url += "&start=" + strconv.FormatUint(uint64(*start), 10) | ||||
| 	} | ||||
| 	req, err := http.NewRequest("GET", url, nil) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return DoInventoryRequest(client, req) | ||||
| } | ||||
|  | ||||
| func GetOwnInventory(client *http.Client, contextId uint64, appId uint32) (*Inventory, error) { | ||||
| 	return GetFullInventory(func() (*PartialInventory, error) { | ||||
| 		return GetPartialOwnInventory(client, contextId, appId, nil) | ||||
| 	}, func(start uint) (*PartialInventory, error) { | ||||
| 		return GetPartialOwnInventory(client, contextId, appId, &start) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										91
									
								
								vendor/github.com/Philipp15b/go-steam/economy/inventory/partial.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										91
									
								
								vendor/github.com/Philipp15b/go-steam/economy/inventory/partial.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,91 +0,0 @@ | ||||
| package inventory | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| // A partial inventory as sent by the Steam API. | ||||
| type PartialInventory struct { | ||||
| 	Success bool | ||||
| 	Error   string | ||||
| 	Inventory | ||||
| 	More      bool | ||||
| 	MoreStart MoreStart `json:"more_start"` | ||||
| } | ||||
|  | ||||
| type MoreStart uint | ||||
|  | ||||
| func (m *MoreStart) UnmarshalJSON(data []byte) error { | ||||
| 	if bytes.Equal(data, []byte("false")) { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return json.Unmarshal(data, (*uint)(m)) | ||||
| } | ||||
|  | ||||
| func DoInventoryRequest(client *http.Client, req *http.Request) (*PartialInventory, error) { | ||||
| 	resp, err := client.Do(req) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	inv := new(PartialInventory) | ||||
| 	err = json.NewDecoder(resp.Body).Decode(inv) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return inv, nil | ||||
| } | ||||
|  | ||||
| func GetFullInventory(getFirst func() (*PartialInventory, error), getNext func(start uint) (*PartialInventory, error)) (*Inventory, error) { | ||||
| 	first, err := getFirst() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if !first.Success { | ||||
| 		return nil, errors.New("GetFullInventory API call failed: " + first.Error) | ||||
| 	} | ||||
|  | ||||
| 	result := &first.Inventory | ||||
| 	var next *PartialInventory | ||||
| 	for latest := first; latest.More; latest = next { | ||||
| 		next, err := getNext(uint(latest.MoreStart)) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if !next.Success { | ||||
| 			return nil, errors.New("GetFullInventory API call failed: " + next.Error) | ||||
| 		} | ||||
|  | ||||
| 		result = Merge(result, &next.Inventory) | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
|  | ||||
| // Merges the given Inventory into a single Inventory. | ||||
| // The given slice must have at least one element. The first element of the slice is used | ||||
| // and modified. | ||||
| func Merge(p ...*Inventory) *Inventory { | ||||
| 	inv := p[0] | ||||
| 	for idx, i := range p { | ||||
| 		if idx == 0 { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		for key, value := range i.Items { | ||||
| 			inv.Items[key] = value | ||||
| 		} | ||||
| 		for key, value := range i.Descriptions { | ||||
| 			inv.Descriptions[key] = value | ||||
| 		} | ||||
| 		for key, value := range i.Currencies { | ||||
| 			inv.Currencies[key] = value | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return inv | ||||
| } | ||||
							
								
								
									
										295
									
								
								vendor/github.com/Philipp15b/go-steam/generator/generator.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										295
									
								
								vendor/github.com/Philipp15b/go-steam/generator/generator.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,295 +0,0 @@ | ||||
| /* | ||||
| This program generates the protobuf and SteamLanguage files from the SteamKit data. | ||||
| */ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	"go/parser" | ||||
| 	"go/token" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| var printCommands = false | ||||
|  | ||||
| func main() { | ||||
| 	args := strings.Join(os.Args[1:], " ") | ||||
|  | ||||
| 	found := false | ||||
| 	if strings.Contains(args, "clean") { | ||||
| 		clean() | ||||
| 		found = true | ||||
| 	} | ||||
| 	if strings.Contains(args, "steamlang") { | ||||
| 		buildSteamLanguage() | ||||
| 		found = true | ||||
| 	} | ||||
| 	if strings.Contains(args, "proto") { | ||||
| 		buildProto() | ||||
| 		found = true | ||||
| 	} | ||||
|  | ||||
| 	if !found { | ||||
| 		os.Stderr.WriteString("Invalid target!\nAvailable targets: clean, proto, steamlang\n") | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func clean() { | ||||
| 	print("# Cleaning") | ||||
| 	cleanGlob("../protocol/**/*.pb.go") | ||||
| 	cleanGlob("../tf2/protocol/**/*.pb.go") | ||||
| 	cleanGlob("../dota/protocol/**/*.pb.go") | ||||
|  | ||||
| 	os.Remove("../protocol/steamlang/enums.go") | ||||
| 	os.Remove("../protocol/steamlang/messages.go") | ||||
| } | ||||
|  | ||||
| func cleanGlob(pattern string) { | ||||
| 	protos, _ := filepath.Glob(pattern) | ||||
| 	for _, proto := range protos { | ||||
| 		err := os.Remove(proto) | ||||
| 		if err != nil { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func buildSteamLanguage() { | ||||
| 	print("# Building Steam Language") | ||||
| 	exePath := "./GoSteamLanguageGenerator/bin/Debug/GoSteamLanguageGenerator.exe" | ||||
|  | ||||
| 	if runtime.GOOS != "windows" { | ||||
| 		execute("mono", exePath, "./SteamKit", "../protocol/steamlang") | ||||
| 	} else { | ||||
| 		execute(exePath, "./SteamKit", "../protocol/steamlang") | ||||
| 	} | ||||
| 	execute("gofmt", "-w", "../protocol/steamlang/enums.go", "../protocol/steamlang/messages.go") | ||||
| } | ||||
|  | ||||
| func buildProto() { | ||||
| 	print("# Building Protobufs") | ||||
|  | ||||
| 	buildProtoMap("steamclient", clientProtoFiles, "../protocol/protobuf") | ||||
| 	buildProtoMap("tf", tf2ProtoFiles, "../tf2/protocol/protobuf") | ||||
| 	buildProtoMap("dota", dotaProtoFiles, "../dota/protocol/protobuf") | ||||
| } | ||||
|  | ||||
| func buildProtoMap(srcSubdir string, files map[string]string, outDir string) { | ||||
| 	os.MkdirAll(outDir, os.ModePerm) | ||||
| 	for proto, out := range files { | ||||
| 		full := filepath.Join(outDir, out) | ||||
| 		compileProto("SteamKit/Resources/Protobufs", srcSubdir, proto, full) | ||||
| 		fixProto(full) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Maps the proto files to their target files. | ||||
| // See `SteamKit/Resources/Protobufs/steamclient/generate-base.bat` for reference. | ||||
| var clientProtoFiles = map[string]string{ | ||||
| 	"steammessages_base.proto":   "base.pb.go", | ||||
| 	"encrypted_app_ticket.proto": "app_ticket.pb.go", | ||||
|  | ||||
| 	"steammessages_clientserver.proto":   "client_server.pb.go", | ||||
| 	"steammessages_clientserver_2.proto": "client_server_2.pb.go", | ||||
|  | ||||
| 	"content_manifest.proto": "content_manifest.pb.go", | ||||
|  | ||||
| 	"steammessages_unified_base.steamclient.proto":      "unified/base.pb.go", | ||||
| 	"steammessages_cloud.steamclient.proto":             "unified/cloud.pb.go", | ||||
| 	"steammessages_credentials.steamclient.proto":       "unified/credentials.pb.go", | ||||
| 	"steammessages_deviceauth.steamclient.proto":        "unified/deviceauth.pb.go", | ||||
| 	"steammessages_gamenotifications.steamclient.proto": "unified/gamenotifications.pb.go", | ||||
| 	"steammessages_offline.steamclient.proto":           "unified/offline.pb.go", | ||||
| 	"steammessages_parental.steamclient.proto":          "unified/parental.pb.go", | ||||
| 	"steammessages_partnerapps.steamclient.proto":       "unified/partnerapps.pb.go", | ||||
| 	"steammessages_player.steamclient.proto":            "unified/player.pb.go", | ||||
| 	"steammessages_publishedfile.steamclient.proto":     "unified/publishedfile.pb.go", | ||||
| } | ||||
|  | ||||
| var tf2ProtoFiles = map[string]string{ | ||||
| 	"base_gcmessages.proto":  "base.pb.go", | ||||
| 	"econ_gcmessages.proto":  "econ.pb.go", | ||||
| 	"gcsdk_gcmessages.proto": "gcsdk.pb.go", | ||||
| 	"tf_gcmessages.proto":    "tf.pb.go", | ||||
| 	"gcsystemmsgs.proto":     "system.pb.go", | ||||
| } | ||||
|  | ||||
| var dotaProtoFiles = map[string]string{ | ||||
| 	"base_gcmessages.proto":                "base.pb.go", | ||||
| 	"econ_gcmessages.proto":                "econ.pb.go", | ||||
| 	"gcsdk_gcmessages.proto":               "gcsdk.pb.go", | ||||
| 	"dota_gcmessages_common.proto":         "dota_common.pb.go", | ||||
| 	"dota_gcmessages_client.proto":         "dota_client.pb.go", | ||||
| 	"dota_gcmessages_client_fantasy.proto": "dota_client_fantasy.pb.go", | ||||
| 	"gcsystemmsgs.proto":                   "system.pb.go", | ||||
| } | ||||
|  | ||||
| func compileProto(srcBase, srcSubdir, proto, target string) { | ||||
| 	outDir, _ := filepath.Split(target) | ||||
| 	err := os.MkdirAll(outDir, os.ModePerm) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	execute("protoc", "--go_out="+outDir, "-I="+srcBase+"/"+srcSubdir, "-I="+srcBase, filepath.Join(srcBase, srcSubdir, proto)) | ||||
| 	out := strings.Replace(filepath.Join(outDir, proto), ".proto", ".pb.go", 1) | ||||
| 	err = forceRename(out, target) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func forceRename(from, to string) error { | ||||
| 	if from != to { | ||||
| 		os.Remove(to) | ||||
| 	} | ||||
| 	return os.Rename(from, to) | ||||
| } | ||||
|  | ||||
| var pkgRegex = regexp.MustCompile(`(package \w+)`) | ||||
| var pkgCommentRegex = regexp.MustCompile(`(?s)(\/\*.*?\*\/\n)package`) | ||||
| var unusedImportCommentRegex = regexp.MustCompile("// discarding unused import .*\n") | ||||
| var fileDescriptorVarRegex = regexp.MustCompile(`fileDescriptor\d+`) | ||||
|  | ||||
| func fixProto(path string) { | ||||
| 	// goprotobuf is really bad at dependencies, so we must fix them manually... | ||||
| 	// It tries to load each dependency of a file as a seperate package (but in a very, very wrong way). | ||||
| 	// Because we want some files in the same package, we'll remove those imports to local files. | ||||
|  | ||||
| 	file, err := ioutil.ReadFile(path) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	fset := token.NewFileSet() | ||||
| 	f, err := parser.ParseFile(fset, path, file, parser.ImportsOnly) | ||||
| 	if err != nil { | ||||
| 		panic("Error parsing " + path + ": " + err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	importsToRemove := make([]*ast.ImportSpec, 0) | ||||
| 	for _, i := range f.Imports { | ||||
| 		// We remove all local imports | ||||
| 		if i.Path.Value == "\".\"" { | ||||
| 			importsToRemove = append(importsToRemove, i) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for _, itr := range importsToRemove { | ||||
| 		// remove the package name from all types | ||||
| 		file = bytes.Replace(file, []byte(itr.Name.Name+"."), []byte{}, -1) | ||||
| 		// and remove the import itself | ||||
| 		file = bytes.Replace(file, []byte(fmt.Sprintf("import %v %v\n", itr.Name.Name, itr.Path.Value)), []byte{}, -1) | ||||
| 	} | ||||
|  | ||||
| 	// remove the package comment because it just includes a list of all messages and | ||||
| 	// collides not only with the other compiled protobuf files, but also our own documentation. | ||||
| 	file = cutAllSubmatch(pkgCommentRegex, file, 1) | ||||
|  | ||||
| 	// remove warnings | ||||
| 	file = unusedImportCommentRegex.ReplaceAllLiteral(file, []byte{}) | ||||
|  | ||||
| 	// fix the package name | ||||
| 	file = pkgRegex.ReplaceAll(file, []byte("package "+inferPackageName(path))) | ||||
|  | ||||
| 	// fix the google dependency; | ||||
| 	// we just reuse the one from protoc-gen-go | ||||
| 	file = bytes.Replace(file, []byte("google/protobuf"), []byte("github.com/golang/protobuf/protoc-gen-go/descriptor"), -1) | ||||
|  | ||||
| 	// we need to prefix local variables created by protoc-gen-go so that they don't clash with others in the same package | ||||
| 	filename := strings.Split(filepath.Base(path), ".")[0] | ||||
| 	file = fileDescriptorVarRegex.ReplaceAllFunc(file, func(match []byte) []byte { | ||||
| 		return []byte(filename + "_" + string(match)) | ||||
| 	}) | ||||
|  | ||||
| 	err = ioutil.WriteFile(path, file, os.ModePerm) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func inferPackageName(path string) string { | ||||
| 	pieces := strings.Split(path, string(filepath.Separator)) | ||||
| 	return pieces[len(pieces)-2] | ||||
| } | ||||
|  | ||||
| func cutAllSubmatch(r *regexp.Regexp, b []byte, n int) []byte { | ||||
| 	i := r.FindSubmatchIndex(b) | ||||
| 	return bytesCut(b, i[2*n], i[2*n+1]) | ||||
| } | ||||
|  | ||||
| // Removes the given section from the byte array | ||||
| func bytesCut(b []byte, from, to int) []byte { | ||||
| 	buf := new(bytes.Buffer) | ||||
| 	buf.Write(b[:from]) | ||||
| 	buf.Write(b[to:]) | ||||
| 	return buf.Bytes() | ||||
| } | ||||
|  | ||||
| func print(text string) { os.Stdout.WriteString(text + "\n") } | ||||
|  | ||||
| func printerr(text string) { os.Stderr.WriteString(text + "\n") } | ||||
|  | ||||
| // This writer appends a "> " after every newline so that the outpout appears quoted. | ||||
| type QuotedWriter struct { | ||||
| 	w       io.Writer | ||||
| 	started bool | ||||
| } | ||||
|  | ||||
| func NewQuotedWriter(w io.Writer) *QuotedWriter { | ||||
| 	return &QuotedWriter{w, false} | ||||
| } | ||||
|  | ||||
| func (w *QuotedWriter) Write(p []byte) (n int, err error) { | ||||
| 	if !w.started { | ||||
| 		_, err = w.w.Write([]byte("> ")) | ||||
| 		if err != nil { | ||||
| 			return n, err | ||||
| 		} | ||||
| 		w.started = true | ||||
| 	} | ||||
|  | ||||
| 	for i, c := range p { | ||||
| 		if c == '\n' { | ||||
| 			nw, err := w.w.Write(p[n : i+1]) | ||||
| 			n += nw | ||||
| 			if err != nil { | ||||
| 				return n, err | ||||
| 			} | ||||
|  | ||||
| 			_, err = w.w.Write([]byte("> ")) | ||||
| 			if err != nil { | ||||
| 				return n, err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if n != len(p) { | ||||
| 		nw, err := w.w.Write(p[n:len(p)]) | ||||
| 		n += nw | ||||
| 		return n, err | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func execute(command string, args ...string) { | ||||
| 	if printCommands { | ||||
| 		print(command + " " + strings.Join(args, " ")) | ||||
| 	} | ||||
| 	cmd := exec.Command(command, args...) | ||||
| 	cmd.Stdout = NewQuotedWriter(os.Stdout) | ||||
| 	cmd.Stderr = NewQuotedWriter(os.Stderr) | ||||
| 	err := cmd.Run() | ||||
| 	if err != nil { | ||||
| 		printerr(err.Error()) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										210
									
								
								vendor/github.com/Philipp15b/go-steam/gsbot/gsbot.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										210
									
								
								vendor/github.com/Philipp15b/go-steam/gsbot/gsbot.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,210 +0,0 @@ | ||||
| // The GsBot package contains some useful utilites for working with the | ||||
| // steam package. It implements authentication with sentries, server lists and | ||||
| // logging messages and events. | ||||
| // | ||||
| // Every module is optional and requires an instance of the GsBot struct. | ||||
| // Should a module have a `HandlePacket` method, you must register it with the | ||||
| // steam.Client with `RegisterPacketHandler`. Any module with a `HandleEvent` | ||||
| // method must be integrated into your event loop and should be called for each | ||||
| // event you receive. | ||||
| package gsbot | ||||
|  | ||||
| import ( | ||||
| 	"encoding/hex" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"math/rand" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"reflect" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/Philipp15b/go-steam" | ||||
| 	"github.com/Philipp15b/go-steam/netutil" | ||||
| 	"github.com/Philipp15b/go-steam/protocol" | ||||
| 	"github.com/davecgh/go-spew/spew" | ||||
| ) | ||||
|  | ||||
| // Base structure holding common data among GsBot modules. | ||||
| type GsBot struct { | ||||
| 	Client *steam.Client | ||||
| 	Log    *log.Logger | ||||
| } | ||||
|  | ||||
| // Creates a new GsBot with a new steam.Client where logs are written to stdout. | ||||
| func Default() *GsBot { | ||||
| 	return &GsBot{ | ||||
| 		steam.NewClient(), | ||||
| 		log.New(os.Stdout, "", 0), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // This module handles authentication. It logs on automatically after a ConnectedEvent | ||||
| // and saves the sentry data to a file which is also used for logon if available. | ||||
| // If you're logging on for the first time Steam may require an authcode. You can then | ||||
| // connect again with the new logon details. | ||||
| type Auth struct { | ||||
| 	bot             *GsBot | ||||
| 	details         *LogOnDetails | ||||
| 	sentryPath      string | ||||
| 	machineAuthHash []byte | ||||
| } | ||||
|  | ||||
| func NewAuth(bot *GsBot, details *LogOnDetails, sentryPath string) *Auth { | ||||
| 	return &Auth{ | ||||
| 		bot:        bot, | ||||
| 		details:    details, | ||||
| 		sentryPath: sentryPath, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type LogOnDetails struct { | ||||
| 	Username      string | ||||
| 	Password      string | ||||
| 	AuthCode      string | ||||
| 	TwoFactorCode string | ||||
| } | ||||
|  | ||||
| // This is called automatically after every ConnectedEvent, but must be called once again manually | ||||
| // with an authcode if Steam requires it when logging on for the first time. | ||||
| func (a *Auth) LogOn(details *LogOnDetails) { | ||||
| 	a.details = details | ||||
| 	sentry, err := ioutil.ReadFile(a.sentryPath) | ||||
| 	if err != nil { | ||||
| 		a.bot.Log.Printf("Error loading sentry file from path %v - This is normal if you're logging in for the first time.\n", a.sentryPath) | ||||
| 	} | ||||
| 	a.bot.Client.Auth.LogOn(&steam.LogOnDetails{ | ||||
| 		Username:       details.Username, | ||||
| 		Password:       details.Password, | ||||
| 		SentryFileHash: sentry, | ||||
| 		AuthCode:       details.AuthCode, | ||||
| 		TwoFactorCode:  details.TwoFactorCode, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func (a *Auth) HandleEvent(event interface{}) { | ||||
| 	switch e := event.(type) { | ||||
| 	case *steam.ConnectedEvent: | ||||
| 		a.LogOn(a.details) | ||||
| 	case *steam.LoggedOnEvent: | ||||
| 		a.bot.Log.Printf("Logged on (%v) with SteamId %v and account flags %v", e.Result, e.ClientSteamId, e.AccountFlags) | ||||
| 	case *steam.MachineAuthUpdateEvent: | ||||
| 		a.machineAuthHash = e.Hash | ||||
| 		err := ioutil.WriteFile(a.sentryPath, e.Hash, 0666) | ||||
| 		if err != nil { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // This module saves the server list from ClientCMListEvent and uses | ||||
| // it when you call `Connect()`. | ||||
| type ServerList struct { | ||||
| 	bot      *GsBot | ||||
| 	listPath string | ||||
| } | ||||
|  | ||||
| func NewServerList(bot *GsBot, listPath string) *ServerList { | ||||
| 	return &ServerList{ | ||||
| 		bot, | ||||
| 		listPath, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s *ServerList) HandleEvent(event interface{}) { | ||||
| 	switch e := event.(type) { | ||||
| 	case *steam.ClientCMListEvent: | ||||
| 		d, err := json.Marshal(e.Addresses) | ||||
| 		if err != nil { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 		err = ioutil.WriteFile(s.listPath, d, 0666) | ||||
| 		if err != nil { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s *ServerList) Connect() (bool, error) { | ||||
| 	return s.ConnectBind(nil) | ||||
| } | ||||
|  | ||||
| func (s *ServerList) ConnectBind(laddr *net.TCPAddr) (bool, error) { | ||||
| 	d, err := ioutil.ReadFile(s.listPath) | ||||
| 	if err != nil { | ||||
| 		s.bot.Log.Println("Connecting to random server.") | ||||
| 		s.bot.Client.Connect() | ||||
| 		return false, nil | ||||
| 	} | ||||
| 	var addrs []*netutil.PortAddr | ||||
| 	err = json.Unmarshal(d, &addrs) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	raddr := addrs[rand.Intn(len(addrs))] | ||||
| 	s.bot.Log.Printf("Connecting to %v from server list\n", raddr) | ||||
| 	s.bot.Client.ConnectToBind(raddr, laddr) | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| // This module logs incoming packets and events to a directory. | ||||
| type Debug struct { | ||||
| 	packetId, eventId uint64 | ||||
| 	bot               *GsBot | ||||
| 	base              string | ||||
| } | ||||
|  | ||||
| func NewDebug(bot *GsBot, base string) (*Debug, error) { | ||||
| 	base = path.Join(base, fmt.Sprint(time.Now().Unix())) | ||||
| 	err := os.MkdirAll(path.Join(base, "events"), 0700) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	err = os.MkdirAll(path.Join(base, "packets"), 0700) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &Debug{ | ||||
| 		0, 0, | ||||
| 		bot, | ||||
| 		base, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func (d *Debug) HandlePacket(packet *protocol.Packet) { | ||||
| 	d.packetId++ | ||||
| 	name := path.Join(d.base, "packets", fmt.Sprintf("%d_%d_%s", time.Now().Unix(), d.packetId, packet.EMsg)) | ||||
|  | ||||
| 	text := packet.String() + "\n\n" + hex.Dump(packet.Data) | ||||
| 	err := ioutil.WriteFile(name+".txt", []byte(text), 0666) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	err = ioutil.WriteFile(name+".bin", packet.Data, 0666) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (d *Debug) HandleEvent(event interface{}) { | ||||
| 	d.eventId++ | ||||
| 	name := fmt.Sprintf("%d_%d_%s.txt", time.Now().Unix(), d.eventId, name(event)) | ||||
| 	err := ioutil.WriteFile(path.Join(d.base, "events", name), []byte(spew.Sdump(event)), 0666) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func name(obj interface{}) string { | ||||
| 	val := reflect.ValueOf(obj) | ||||
| 	ind := reflect.Indirect(val) | ||||
| 	if ind.IsValid() { | ||||
| 		return ind.Type().Name() | ||||
| 	} else { | ||||
| 		return val.Type().Name() | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										56
									
								
								vendor/github.com/Philipp15b/go-steam/gsbot/gsbot/gsbot.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										56
									
								
								vendor/github.com/Philipp15b/go-steam/gsbot/gsbot/gsbot.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,56 +0,0 @@ | ||||
| // A simple example that uses the modules from the gsbot package and go-steam to log on | ||||
| // to the Steam network. | ||||
| // | ||||
| // The command expects log on data, optionally with an auth code: | ||||
| // | ||||
| //     gsbot [username] [password] | ||||
| //     gsbot [username] [password] [authcode] | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/Philipp15b/go-steam" | ||||
| 	"github.com/Philipp15b/go-steam/gsbot" | ||||
| 	"github.com/Philipp15b/go-steam/protocol/steamlang" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	if len(os.Args) < 3 { | ||||
| 		fmt.Println("gsbot example\nusage: \n\tgsbot [username] [password] [authcode]") | ||||
| 		return | ||||
| 	} | ||||
| 	authcode := "" | ||||
| 	if len(os.Args) > 3 { | ||||
| 		authcode = os.Args[3] | ||||
| 	} | ||||
|  | ||||
| 	bot := gsbot.Default() | ||||
| 	client := bot.Client | ||||
| 	auth := gsbot.NewAuth(bot, &gsbot.LogOnDetails{ | ||||
| 		os.Args[1], | ||||
| 		os.Args[2], | ||||
| 		authcode, | ||||
| 	}, "sentry.bin") | ||||
| 	debug, err := gsbot.NewDebug(bot, "debug") | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	client.RegisterPacketHandler(debug) | ||||
| 	serverList := gsbot.NewServerList(bot, "serverlist.json") | ||||
| 	serverList.Connect() | ||||
|  | ||||
| 	for event := range client.Events() { | ||||
| 		auth.HandleEvent(event) | ||||
| 		debug.HandleEvent(event) | ||||
| 		serverList.HandleEvent(event) | ||||
|  | ||||
| 		switch e := event.(type) { | ||||
| 		case error: | ||||
| 			fmt.Printf("Error: %v", e) | ||||
| 		case *steam.LoggedOnEvent: | ||||
| 			client.Social.SetPersonaState(steamlang.EPersonaState_Online) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										19
									
								
								vendor/github.com/Philipp15b/go-steam/jsont/jsont.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/Philipp15b/go-steam/jsont/jsont.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,19 +0,0 @@ | ||||
| // Includes helper types for working with JSON data | ||||
| package jsont | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| ) | ||||
|  | ||||
| // A boolean value that can be unmarshaled from a number in JSON. | ||||
| type UintBool bool | ||||
|  | ||||
| func (u *UintBool) UnmarshalJSON(data []byte) error { | ||||
| 	var n uint | ||||
| 	err := json.Unmarshal(data, &n) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*u = n != 0 | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										141
									
								
								vendor/github.com/Philipp15b/go-steam/protocol/protobuf/unified/base.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										141
									
								
								vendor/github.com/Philipp15b/go-steam/protocol/protobuf/unified/base.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,141 +0,0 @@ | ||||
| // Code generated by protoc-gen-go. | ||||
| // source: steammessages_unified_base.steamclient.proto | ||||
| // DO NOT EDIT! | ||||
|  | ||||
| package unified | ||||
|  | ||||
| import proto "github.com/golang/protobuf/proto" | ||||
| import fmt "fmt" | ||||
| import math "math" | ||||
| import google_protobuf "github.com/golang/protobuf/protoc-gen-go/descriptor" | ||||
|  | ||||
| // Reference imports to suppress errors if they are not otherwise used. | ||||
| var _ = proto.Marshal | ||||
| var _ = fmt.Errorf | ||||
| var _ = math.Inf | ||||
|  | ||||
| type EProtoExecutionSite int32 | ||||
|  | ||||
| const ( | ||||
| 	EProtoExecutionSite_k_EProtoExecutionSiteUnknown     EProtoExecutionSite = 0 | ||||
| 	EProtoExecutionSite_k_EProtoExecutionSiteSteamClient EProtoExecutionSite = 2 | ||||
| ) | ||||
|  | ||||
| var EProtoExecutionSite_name = map[int32]string{ | ||||
| 	0: "k_EProtoExecutionSiteUnknown", | ||||
| 	2: "k_EProtoExecutionSiteSteamClient", | ||||
| } | ||||
| var EProtoExecutionSite_value = map[string]int32{ | ||||
| 	"k_EProtoExecutionSiteUnknown":     0, | ||||
| 	"k_EProtoExecutionSiteSteamClient": 2, | ||||
| } | ||||
|  | ||||
| func (x EProtoExecutionSite) Enum() *EProtoExecutionSite { | ||||
| 	p := new(EProtoExecutionSite) | ||||
| 	*p = x | ||||
| 	return p | ||||
| } | ||||
| func (x EProtoExecutionSite) String() string { | ||||
| 	return proto.EnumName(EProtoExecutionSite_name, int32(x)) | ||||
| } | ||||
| func (x *EProtoExecutionSite) UnmarshalJSON(data []byte) error { | ||||
| 	value, err := proto.UnmarshalJSONEnum(EProtoExecutionSite_value, data, "EProtoExecutionSite") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*x = EProtoExecutionSite(value) | ||||
| 	return nil | ||||
| } | ||||
| func (EProtoExecutionSite) EnumDescriptor() ([]byte, []int) { return base_fileDescriptor0, []int{0} } | ||||
|  | ||||
| type NoResponse struct { | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *NoResponse) Reset()                    { *m = NoResponse{} } | ||||
| func (m *NoResponse) String() string            { return proto.CompactTextString(m) } | ||||
| func (*NoResponse) ProtoMessage()               {} | ||||
| func (*NoResponse) Descriptor() ([]byte, []int) { return base_fileDescriptor0, []int{0} } | ||||
|  | ||||
| var E_Description = &proto.ExtensionDesc{ | ||||
| 	ExtendedType:  (*google_protobuf.FieldOptions)(nil), | ||||
| 	ExtensionType: (*string)(nil), | ||||
| 	Field:         50000, | ||||
| 	Name:          "description", | ||||
| 	Tag:           "bytes,50000,opt,name=description", | ||||
| } | ||||
|  | ||||
| var E_ServiceDescription = &proto.ExtensionDesc{ | ||||
| 	ExtendedType:  (*google_protobuf.ServiceOptions)(nil), | ||||
| 	ExtensionType: (*string)(nil), | ||||
| 	Field:         50000, | ||||
| 	Name:          "service_description", | ||||
| 	Tag:           "bytes,50000,opt,name=service_description", | ||||
| } | ||||
|  | ||||
| var E_ServiceExecutionSite = &proto.ExtensionDesc{ | ||||
| 	ExtendedType:  (*google_protobuf.ServiceOptions)(nil), | ||||
| 	ExtensionType: (*EProtoExecutionSite)(nil), | ||||
| 	Field:         50008, | ||||
| 	Name:          "service_execution_site", | ||||
| 	Tag:           "varint,50008,opt,name=service_execution_site,enum=EProtoExecutionSite,def=0", | ||||
| } | ||||
|  | ||||
| var E_MethodDescription = &proto.ExtensionDesc{ | ||||
| 	ExtendedType:  (*google_protobuf.MethodOptions)(nil), | ||||
| 	ExtensionType: (*string)(nil), | ||||
| 	Field:         50000, | ||||
| 	Name:          "method_description", | ||||
| 	Tag:           "bytes,50000,opt,name=method_description", | ||||
| } | ||||
|  | ||||
| var E_EnumDescription = &proto.ExtensionDesc{ | ||||
| 	ExtendedType:  (*google_protobuf.EnumOptions)(nil), | ||||
| 	ExtensionType: (*string)(nil), | ||||
| 	Field:         50000, | ||||
| 	Name:          "enum_description", | ||||
| 	Tag:           "bytes,50000,opt,name=enum_description", | ||||
| } | ||||
|  | ||||
| var E_EnumValueDescription = &proto.ExtensionDesc{ | ||||
| 	ExtendedType:  (*google_protobuf.EnumValueOptions)(nil), | ||||
| 	ExtensionType: (*string)(nil), | ||||
| 	Field:         50000, | ||||
| 	Name:          "enum_value_description", | ||||
| 	Tag:           "bytes,50000,opt,name=enum_value_description", | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	proto.RegisterType((*NoResponse)(nil), "NoResponse") | ||||
| 	proto.RegisterEnum("EProtoExecutionSite", EProtoExecutionSite_name, EProtoExecutionSite_value) | ||||
| 	proto.RegisterExtension(E_Description) | ||||
| 	proto.RegisterExtension(E_ServiceDescription) | ||||
| 	proto.RegisterExtension(E_ServiceExecutionSite) | ||||
| 	proto.RegisterExtension(E_MethodDescription) | ||||
| 	proto.RegisterExtension(E_EnumDescription) | ||||
| 	proto.RegisterExtension(E_EnumValueDescription) | ||||
| } | ||||
|  | ||||
| var base_fileDescriptor0 = []byte{ | ||||
| 	// 306 bytes of a gzipped FileDescriptorProto | ||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x90, 0x4d, 0x4b, 0xc3, 0x40, | ||||
| 	0x10, 0x86, 0x1b, 0xc5, 0x83, 0xa3, 0x48, 0x48, 0xa5, 0x88, 0x54, 0x8d, 0xe2, 0x41, 0x44, 0xb6, | ||||
| 	0x20, 0x1e, 0x24, 0x88, 0x07, 0x4b, 0xc4, 0x8b, 0x1f, 0x18, 0xf4, 0x26, 0x21, 0x4d, 0xa6, 0x71, | ||||
| 	0x69, 0xb2, 0x1b, 0xb2, 0xbb, 0xd5, 0xa3, 0x27, 0x7f, 0x9f, 0x47, 0x7f, 0x8e, 0xcd, 0x86, 0x80, | ||||
| 	0xf9, 0x40, 0x8f, 0xc9, 0xfb, 0x3e, 0xb3, 0xcf, 0x0c, 0x9c, 0x08, 0x89, 0x41, 0x9a, 0xa2, 0x10, | ||||
| 	0x41, 0x8c, 0xc2, 0x57, 0x8c, 0x4e, 0x29, 0x46, 0xfe, 0x24, 0x10, 0x48, 0x74, 0x14, 0x26, 0x14, | ||||
| 	0x99, 0x24, 0x59, 0xce, 0x25, 0xdf, 0xb6, 0x63, 0xce, 0xe3, 0x04, 0x47, 0xfa, 0x6b, 0xa2, 0xa6, | ||||
| 	0xa3, 0x08, 0x45, 0x98, 0xd3, 0x4c, 0xf2, 0xbc, 0x6c, 0x1c, 0xac, 0x03, 0xdc, 0xf1, 0x47, 0x14, | ||||
| 	0x19, 0x67, 0x02, 0x8f, 0x5f, 0xa0, 0xef, 0x3e, 0x14, 0xff, 0xdd, 0x77, 0x0c, 0x95, 0xa4, 0x9c, | ||||
| 	0x79, 0x54, 0xa2, 0x65, 0xc3, 0x70, 0xe6, 0x77, 0x04, 0x4f, 0x6c, 0xc6, 0xf8, 0x1b, 0x33, 0x7b, | ||||
| 	0xd6, 0x21, 0xd8, 0x9d, 0x0d, 0xaf, 0x50, 0x1a, 0x6b, 0x25, 0x73, 0xc9, 0x39, 0x83, 0xb5, 0x4a, | ||||
| 	0x60, 0x91, 0x5b, 0x3b, 0xa4, 0xd4, 0x23, 0x95, 0x1e, 0xb9, 0xa6, 0x98, 0x44, 0xf7, 0x3a, 0x15, | ||||
| 	0x5b, 0x5f, 0x9f, 0xcb, 0xb6, 0x71, 0xb4, 0xea, 0x5c, 0x42, 0x5f, 0x60, 0x3e, 0xa7, 0x21, 0xfa, | ||||
| 	0xbf, 0xe9, 0xbd, 0x16, 0xed, 0x95, 0xad, 0x26, 0xaf, 0x60, 0x50, 0xf1, 0x58, 0xb9, 0xf9, 0xa2, | ||||
| 	0xd8, 0xeb, 0xdf, 0x11, 0xdf, 0x7a, 0xc4, 0xc6, 0xe9, 0x26, 0xe9, 0xd8, 0xcd, 0xf9, 0xf3, 0x28, | ||||
| 	0xce, 0x05, 0x58, 0x29, 0xca, 0x57, 0x1e, 0xd5, 0xac, 0x77, 0x5b, 0x4f, 0xde, 0xea, 0x52, 0x53, | ||||
| 	0xfa, 0x1c, 0x4c, 0x64, 0x2a, 0xad, 0xb1, 0xc3, 0x16, 0xeb, 0x2e, 0x2a, 0x4d, 0x72, 0x0c, 0x03, | ||||
| 	0x4d, 0xce, 0x83, 0x44, 0xd5, 0x2f, 0xb6, 0xdf, 0xc9, 0x3f, 0x17, 0xbd, 0xc6, 0x90, 0xab, 0x95, | ||||
| 	0x1b, 0xe3, 0xc3, 0xe8, 0xfd, 0x04, 0x00, 0x00, 0xff, 0xff, 0x5c, 0xf6, 0x07, 0xbb, 0x6e, 0x02, | ||||
| 	0x00, 0x00, | ||||
| } | ||||
							
								
								
									
										1424
									
								
								vendor/github.com/Philipp15b/go-steam/protocol/protobuf/unified/cloud.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1424
									
								
								vendor/github.com/Philipp15b/go-steam/protocol/protobuf/unified/cloud.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										874
									
								
								vendor/github.com/Philipp15b/go-steam/protocol/protobuf/unified/credentials.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										874
									
								
								vendor/github.com/Philipp15b/go-steam/protocol/protobuf/unified/credentials.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,874 +0,0 @@ | ||||
| // Code generated by protoc-gen-go. | ||||
| // source: steammessages_credentials.steamclient.proto | ||||
| // DO NOT EDIT! | ||||
|  | ||||
| package unified | ||||
|  | ||||
| import proto "github.com/golang/protobuf/proto" | ||||
| import fmt "fmt" | ||||
| import math "math" | ||||
|  | ||||
| // Reference imports to suppress errors if they are not otherwise used. | ||||
| var _ = proto.Marshal | ||||
| var _ = fmt.Errorf | ||||
| var _ = math.Inf | ||||
|  | ||||
| type CCredentials_TestAvailablePassword_Request struct { | ||||
| 	Password          *string `protobuf:"bytes,1,opt,name=password" json:"password,omitempty"` | ||||
| 	ShaDigestPassword []byte  `protobuf:"bytes,2,opt,name=sha_digest_password" json:"sha_digest_password,omitempty"` | ||||
| 	AccountName       *string `protobuf:"bytes,3,opt,name=account_name" json:"account_name,omitempty"` | ||||
| 	XXX_unrecognized  []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_TestAvailablePassword_Request) Reset() { | ||||
| 	*m = CCredentials_TestAvailablePassword_Request{} | ||||
| } | ||||
| func (m *CCredentials_TestAvailablePassword_Request) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CCredentials_TestAvailablePassword_Request) ProtoMessage() {} | ||||
| func (*CCredentials_TestAvailablePassword_Request) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{0} | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_TestAvailablePassword_Request) GetPassword() string { | ||||
| 	if m != nil && m.Password != nil { | ||||
| 		return *m.Password | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_TestAvailablePassword_Request) GetShaDigestPassword() []byte { | ||||
| 	if m != nil { | ||||
| 		return m.ShaDigestPassword | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_TestAvailablePassword_Request) GetAccountName() string { | ||||
| 	if m != nil && m.AccountName != nil { | ||||
| 		return *m.AccountName | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| type CCredentials_TestAvailablePassword_Response struct { | ||||
| 	IsValid          *bool  `protobuf:"varint,3,opt,name=is_valid" json:"is_valid,omitempty"` | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_TestAvailablePassword_Response) Reset() { | ||||
| 	*m = CCredentials_TestAvailablePassword_Response{} | ||||
| } | ||||
| func (m *CCredentials_TestAvailablePassword_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CCredentials_TestAvailablePassword_Response) ProtoMessage() {} | ||||
| func (*CCredentials_TestAvailablePassword_Response) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{1} | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_TestAvailablePassword_Response) GetIsValid() bool { | ||||
| 	if m != nil && m.IsValid != nil { | ||||
| 		return *m.IsValid | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| type CCredentials_GetSteamGuardDetails_Request struct { | ||||
| 	IncludeNewAuthentications *bool   `protobuf:"varint,1,opt,name=include_new_authentications,def=1" json:"include_new_authentications,omitempty"` | ||||
| 	Webcookie                 *string `protobuf:"bytes,2,opt,name=webcookie" json:"webcookie,omitempty"` | ||||
| 	TimestampMinimumWanted    *uint32 `protobuf:"fixed32,3,opt,name=timestamp_minimum_wanted" json:"timestamp_minimum_wanted,omitempty"` | ||||
| 	Ipaddress                 *int32  `protobuf:"varint,4,opt,name=ipaddress" json:"ipaddress,omitempty"` | ||||
| 	XXX_unrecognized          []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Request) Reset() { | ||||
| 	*m = CCredentials_GetSteamGuardDetails_Request{} | ||||
| } | ||||
| func (m *CCredentials_GetSteamGuardDetails_Request) String() string { return proto.CompactTextString(m) } | ||||
| func (*CCredentials_GetSteamGuardDetails_Request) ProtoMessage()    {} | ||||
| func (*CCredentials_GetSteamGuardDetails_Request) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{2} | ||||
| } | ||||
|  | ||||
| const Default_CCredentials_GetSteamGuardDetails_Request_IncludeNewAuthentications bool = true | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Request) GetIncludeNewAuthentications() bool { | ||||
| 	if m != nil && m.IncludeNewAuthentications != nil { | ||||
| 		return *m.IncludeNewAuthentications | ||||
| 	} | ||||
| 	return Default_CCredentials_GetSteamGuardDetails_Request_IncludeNewAuthentications | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Request) GetWebcookie() string { | ||||
| 	if m != nil && m.Webcookie != nil { | ||||
| 		return *m.Webcookie | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Request) GetTimestampMinimumWanted() uint32 { | ||||
| 	if m != nil && m.TimestampMinimumWanted != nil { | ||||
| 		return *m.TimestampMinimumWanted | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Request) GetIpaddress() int32 { | ||||
| 	if m != nil && m.Ipaddress != nil { | ||||
| 		return *m.Ipaddress | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CCredentials_GetSteamGuardDetails_Response struct { | ||||
| 	IsSteamguardEnabled                                   *bool                                                           `protobuf:"varint,1,opt,name=is_steamguard_enabled" json:"is_steamguard_enabled,omitempty"` | ||||
| 	TimestampSteamguardEnabled                            *uint32                                                         `protobuf:"fixed32,2,opt,name=timestamp_steamguard_enabled" json:"timestamp_steamguard_enabled,omitempty"` | ||||
| 	DeprecatedNewauthentication                           []*CCredentials_GetSteamGuardDetails_Response_NewAuthentication `protobuf:"bytes,3,rep,name=deprecated_newauthentication" json:"deprecated_newauthentication,omitempty"` | ||||
| 	DeprecatedMachineNameUserchosen                       *string                                                         `protobuf:"bytes,4,opt,name=deprecated_machine_name_userchosen" json:"deprecated_machine_name_userchosen,omitempty"` | ||||
| 	DeprecatedTimestampMachineSteamguardEnabled           *uint32                                                         `protobuf:"fixed32,5,opt,name=deprecated_timestamp_machine_steamguard_enabled" json:"deprecated_timestamp_machine_steamguard_enabled,omitempty"` | ||||
| 	DeprecatedAuthenticationExistsFromGeolocBeforeMintime *bool                                                           `protobuf:"varint,6,opt,name=deprecated_authentication_exists_from_geoloc_before_mintime" json:"deprecated_authentication_exists_from_geoloc_before_mintime,omitempty"` | ||||
| 	DeprecatedMachineId                                   *uint64                                                         `protobuf:"varint,7,opt,name=deprecated_machine_id" json:"deprecated_machine_id,omitempty"` | ||||
| 	SessionData                                           []*CCredentials_GetSteamGuardDetails_Response_SessionData       `protobuf:"bytes,8,rep,name=session_data" json:"session_data,omitempty"` | ||||
| 	IsTwofactorEnabled                                    *bool                                                           `protobuf:"varint,9,opt,name=is_twofactor_enabled" json:"is_twofactor_enabled,omitempty"` | ||||
| 	TimestampTwofactorEnabled                             *uint32                                                         `protobuf:"fixed32,10,opt,name=timestamp_twofactor_enabled" json:"timestamp_twofactor_enabled,omitempty"` | ||||
| 	IsPhoneVerified                                       *bool                                                           `protobuf:"varint,11,opt,name=is_phone_verified" json:"is_phone_verified,omitempty"` | ||||
| 	XXX_unrecognized                                      []byte                                                          `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response) Reset() { | ||||
| 	*m = CCredentials_GetSteamGuardDetails_Response{} | ||||
| } | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CCredentials_GetSteamGuardDetails_Response) ProtoMessage() {} | ||||
| func (*CCredentials_GetSteamGuardDetails_Response) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{3} | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response) GetIsSteamguardEnabled() bool { | ||||
| 	if m != nil && m.IsSteamguardEnabled != nil { | ||||
| 		return *m.IsSteamguardEnabled | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response) GetTimestampSteamguardEnabled() uint32 { | ||||
| 	if m != nil && m.TimestampSteamguardEnabled != nil { | ||||
| 		return *m.TimestampSteamguardEnabled | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response) GetDeprecatedNewauthentication() []*CCredentials_GetSteamGuardDetails_Response_NewAuthentication { | ||||
| 	if m != nil { | ||||
| 		return m.DeprecatedNewauthentication | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response) GetDeprecatedMachineNameUserchosen() string { | ||||
| 	if m != nil && m.DeprecatedMachineNameUserchosen != nil { | ||||
| 		return *m.DeprecatedMachineNameUserchosen | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response) GetDeprecatedTimestampMachineSteamguardEnabled() uint32 { | ||||
| 	if m != nil && m.DeprecatedTimestampMachineSteamguardEnabled != nil { | ||||
| 		return *m.DeprecatedTimestampMachineSteamguardEnabled | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response) GetDeprecatedAuthenticationExistsFromGeolocBeforeMintime() bool { | ||||
| 	if m != nil && m.DeprecatedAuthenticationExistsFromGeolocBeforeMintime != nil { | ||||
| 		return *m.DeprecatedAuthenticationExistsFromGeolocBeforeMintime | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response) GetDeprecatedMachineId() uint64 { | ||||
| 	if m != nil && m.DeprecatedMachineId != nil { | ||||
| 		return *m.DeprecatedMachineId | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response) GetSessionData() []*CCredentials_GetSteamGuardDetails_Response_SessionData { | ||||
| 	if m != nil { | ||||
| 		return m.SessionData | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response) GetIsTwofactorEnabled() bool { | ||||
| 	if m != nil && m.IsTwofactorEnabled != nil { | ||||
| 		return *m.IsTwofactorEnabled | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response) GetTimestampTwofactorEnabled() uint32 { | ||||
| 	if m != nil && m.TimestampTwofactorEnabled != nil { | ||||
| 		return *m.TimestampTwofactorEnabled | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response) GetIsPhoneVerified() bool { | ||||
| 	if m != nil && m.IsPhoneVerified != nil { | ||||
| 		return *m.IsPhoneVerified | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| type CCredentials_GetSteamGuardDetails_Response_NewAuthentication struct { | ||||
| 	TimestampSteamguardEnabled *uint32 `protobuf:"fixed32,1,opt,name=timestamp_steamguard_enabled" json:"timestamp_steamguard_enabled,omitempty"` | ||||
| 	IsWebCookie                *bool   `protobuf:"varint,2,opt,name=is_web_cookie" json:"is_web_cookie,omitempty"` | ||||
| 	Ipaddress                  *int32  `protobuf:"varint,3,opt,name=ipaddress" json:"ipaddress,omitempty"` | ||||
| 	GeolocInfo                 *string `protobuf:"bytes,4,opt,name=geoloc_info" json:"geoloc_info,omitempty"` | ||||
| 	IsRemembered               *bool   `protobuf:"varint,5,opt,name=is_remembered" json:"is_remembered,omitempty"` | ||||
| 	MachineNameUserSupplied    *string `protobuf:"bytes,6,opt,name=machine_name_user_supplied" json:"machine_name_user_supplied,omitempty"` | ||||
| 	Status                     *int32  `protobuf:"varint,7,opt,name=status" json:"status,omitempty"` | ||||
| 	XXX_unrecognized           []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_NewAuthentication) Reset() { | ||||
| 	*m = CCredentials_GetSteamGuardDetails_Response_NewAuthentication{} | ||||
| } | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_NewAuthentication) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CCredentials_GetSteamGuardDetails_Response_NewAuthentication) ProtoMessage() {} | ||||
| func (*CCredentials_GetSteamGuardDetails_Response_NewAuthentication) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{3, 0} | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_NewAuthentication) GetTimestampSteamguardEnabled() uint32 { | ||||
| 	if m != nil && m.TimestampSteamguardEnabled != nil { | ||||
| 		return *m.TimestampSteamguardEnabled | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_NewAuthentication) GetIsWebCookie() bool { | ||||
| 	if m != nil && m.IsWebCookie != nil { | ||||
| 		return *m.IsWebCookie | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_NewAuthentication) GetIpaddress() int32 { | ||||
| 	if m != nil && m.Ipaddress != nil { | ||||
| 		return *m.Ipaddress | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_NewAuthentication) GetGeolocInfo() string { | ||||
| 	if m != nil && m.GeolocInfo != nil { | ||||
| 		return *m.GeolocInfo | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_NewAuthentication) GetIsRemembered() bool { | ||||
| 	if m != nil && m.IsRemembered != nil { | ||||
| 		return *m.IsRemembered | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_NewAuthentication) GetMachineNameUserSupplied() string { | ||||
| 	if m != nil && m.MachineNameUserSupplied != nil { | ||||
| 		return *m.MachineNameUserSupplied | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_NewAuthentication) GetStatus() int32 { | ||||
| 	if m != nil && m.Status != nil { | ||||
| 		return *m.Status | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CCredentials_GetSteamGuardDetails_Response_SessionData struct { | ||||
| 	MachineId                                   *uint64                                                         `protobuf:"varint,1,opt,name=machine_id" json:"machine_id,omitempty"` | ||||
| 	MachineNameUserchosen                       *string                                                         `protobuf:"bytes,2,opt,name=machine_name_userchosen" json:"machine_name_userchosen,omitempty"` | ||||
| 	TimestampMachineSteamguardEnabled           *uint32                                                         `protobuf:"fixed32,3,opt,name=timestamp_machine_steamguard_enabled" json:"timestamp_machine_steamguard_enabled,omitempty"` | ||||
| 	AuthenticationExistsFromGeolocBeforeMintime *bool                                                           `protobuf:"varint,4,opt,name=authentication_exists_from_geoloc_before_mintime" json:"authentication_exists_from_geoloc_before_mintime,omitempty"` | ||||
| 	Newauthentication                           []*CCredentials_GetSteamGuardDetails_Response_NewAuthentication `protobuf:"bytes,5,rep,name=newauthentication" json:"newauthentication,omitempty"` | ||||
| 	AuthenticationExistsFromSameIpBeforeMintime *bool                                                           `protobuf:"varint,6,opt,name=authentication_exists_from_same_ip_before_mintime" json:"authentication_exists_from_same_ip_before_mintime,omitempty"` | ||||
| 	PublicIpv4                                  *uint32                                                         `protobuf:"varint,7,opt,name=public_ipv4" json:"public_ipv4,omitempty"` | ||||
| 	XXX_unrecognized                            []byte                                                          `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_SessionData) Reset() { | ||||
| 	*m = CCredentials_GetSteamGuardDetails_Response_SessionData{} | ||||
| } | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_SessionData) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CCredentials_GetSteamGuardDetails_Response_SessionData) ProtoMessage() {} | ||||
| func (*CCredentials_GetSteamGuardDetails_Response_SessionData) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{3, 1} | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_SessionData) GetMachineId() uint64 { | ||||
| 	if m != nil && m.MachineId != nil { | ||||
| 		return *m.MachineId | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_SessionData) GetMachineNameUserchosen() string { | ||||
| 	if m != nil && m.MachineNameUserchosen != nil { | ||||
| 		return *m.MachineNameUserchosen | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_SessionData) GetTimestampMachineSteamguardEnabled() uint32 { | ||||
| 	if m != nil && m.TimestampMachineSteamguardEnabled != nil { | ||||
| 		return *m.TimestampMachineSteamguardEnabled | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_SessionData) GetAuthenticationExistsFromGeolocBeforeMintime() bool { | ||||
| 	if m != nil && m.AuthenticationExistsFromGeolocBeforeMintime != nil { | ||||
| 		return *m.AuthenticationExistsFromGeolocBeforeMintime | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_SessionData) GetNewauthentication() []*CCredentials_GetSteamGuardDetails_Response_NewAuthentication { | ||||
| 	if m != nil { | ||||
| 		return m.Newauthentication | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_SessionData) GetAuthenticationExistsFromSameIpBeforeMintime() bool { | ||||
| 	if m != nil && m.AuthenticationExistsFromSameIpBeforeMintime != nil { | ||||
| 		return *m.AuthenticationExistsFromSameIpBeforeMintime | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetSteamGuardDetails_Response_SessionData) GetPublicIpv4() uint32 { | ||||
| 	if m != nil && m.PublicIpv4 != nil { | ||||
| 		return *m.PublicIpv4 | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CCredentials_NewMachineNotificationDialog_Request struct { | ||||
| 	IsApproved       *bool  `protobuf:"varint,1,opt,name=is_approved" json:"is_approved,omitempty"` | ||||
| 	IsWizardComplete *bool  `protobuf:"varint,2,opt,name=is_wizard_complete" json:"is_wizard_complete,omitempty"` | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_NewMachineNotificationDialog_Request) Reset() { | ||||
| 	*m = CCredentials_NewMachineNotificationDialog_Request{} | ||||
| } | ||||
| func (m *CCredentials_NewMachineNotificationDialog_Request) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CCredentials_NewMachineNotificationDialog_Request) ProtoMessage() {} | ||||
| func (*CCredentials_NewMachineNotificationDialog_Request) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{4} | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_NewMachineNotificationDialog_Request) GetIsApproved() bool { | ||||
| 	if m != nil && m.IsApproved != nil { | ||||
| 		return *m.IsApproved | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_NewMachineNotificationDialog_Request) GetIsWizardComplete() bool { | ||||
| 	if m != nil && m.IsWizardComplete != nil { | ||||
| 		return *m.IsWizardComplete | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| type CCredentials_NewMachineNotificationDialog_Response struct { | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_NewMachineNotificationDialog_Response) Reset() { | ||||
| 	*m = CCredentials_NewMachineNotificationDialog_Response{} | ||||
| } | ||||
| func (m *CCredentials_NewMachineNotificationDialog_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CCredentials_NewMachineNotificationDialog_Response) ProtoMessage() {} | ||||
| func (*CCredentials_NewMachineNotificationDialog_Response) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{5} | ||||
| } | ||||
|  | ||||
| type CCredentials_ValidateEmailAddress_Request struct { | ||||
| 	Stoken           *string `protobuf:"bytes,1,opt,name=stoken" json:"stoken,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_ValidateEmailAddress_Request) Reset() { | ||||
| 	*m = CCredentials_ValidateEmailAddress_Request{} | ||||
| } | ||||
| func (m *CCredentials_ValidateEmailAddress_Request) String() string { return proto.CompactTextString(m) } | ||||
| func (*CCredentials_ValidateEmailAddress_Request) ProtoMessage()    {} | ||||
| func (*CCredentials_ValidateEmailAddress_Request) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{6} | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_ValidateEmailAddress_Request) GetStoken() string { | ||||
| 	if m != nil && m.Stoken != nil { | ||||
| 		return *m.Stoken | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| type CCredentials_ValidateEmailAddress_Response struct { | ||||
| 	WasValidated     *bool  `protobuf:"varint,1,opt,name=was_validated" json:"was_validated,omitempty"` | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_ValidateEmailAddress_Response) Reset() { | ||||
| 	*m = CCredentials_ValidateEmailAddress_Response{} | ||||
| } | ||||
| func (m *CCredentials_ValidateEmailAddress_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CCredentials_ValidateEmailAddress_Response) ProtoMessage() {} | ||||
| func (*CCredentials_ValidateEmailAddress_Response) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{7} | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_ValidateEmailAddress_Response) GetWasValidated() bool { | ||||
| 	if m != nil && m.WasValidated != nil { | ||||
| 		return *m.WasValidated | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| type CCredentials_SteamGuardPhishingReport_Request struct { | ||||
| 	ParamString      *string `protobuf:"bytes,1,opt,name=param_string" json:"param_string,omitempty"` | ||||
| 	IpaddressActual  *uint32 `protobuf:"varint,2,opt,name=ipaddress_actual" json:"ipaddress_actual,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_SteamGuardPhishingReport_Request) Reset() { | ||||
| 	*m = CCredentials_SteamGuardPhishingReport_Request{} | ||||
| } | ||||
| func (m *CCredentials_SteamGuardPhishingReport_Request) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CCredentials_SteamGuardPhishingReport_Request) ProtoMessage() {} | ||||
| func (*CCredentials_SteamGuardPhishingReport_Request) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{8} | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_SteamGuardPhishingReport_Request) GetParamString() string { | ||||
| 	if m != nil && m.ParamString != nil { | ||||
| 		return *m.ParamString | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_SteamGuardPhishingReport_Request) GetIpaddressActual() uint32 { | ||||
| 	if m != nil && m.IpaddressActual != nil { | ||||
| 		return *m.IpaddressActual | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CCredentials_SteamGuardPhishingReport_Response struct { | ||||
| 	IpaddressLoginattempt   *uint32 `protobuf:"varint,1,opt,name=ipaddress_loginattempt" json:"ipaddress_loginattempt,omitempty"` | ||||
| 	CountrynameLoginattempt *string `protobuf:"bytes,2,opt,name=countryname_loginattempt" json:"countryname_loginattempt,omitempty"` | ||||
| 	StatenameLoginattempt   *string `protobuf:"bytes,3,opt,name=statename_loginattempt" json:"statename_loginattempt,omitempty"` | ||||
| 	CitynameLoginattempt    *string `protobuf:"bytes,4,opt,name=cityname_loginattempt" json:"cityname_loginattempt,omitempty"` | ||||
| 	IpaddressActual         *uint32 `protobuf:"varint,5,opt,name=ipaddress_actual" json:"ipaddress_actual,omitempty"` | ||||
| 	CountrynameActual       *string `protobuf:"bytes,6,opt,name=countryname_actual" json:"countryname_actual,omitempty"` | ||||
| 	StatenameActual         *string `protobuf:"bytes,7,opt,name=statename_actual" json:"statename_actual,omitempty"` | ||||
| 	CitynameActual          *string `protobuf:"bytes,8,opt,name=cityname_actual" json:"cityname_actual,omitempty"` | ||||
| 	SteamguardCode          *string `protobuf:"bytes,9,opt,name=steamguard_code" json:"steamguard_code,omitempty"` | ||||
| 	XXX_unrecognized        []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_SteamGuardPhishingReport_Response) Reset() { | ||||
| 	*m = CCredentials_SteamGuardPhishingReport_Response{} | ||||
| } | ||||
| func (m *CCredentials_SteamGuardPhishingReport_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CCredentials_SteamGuardPhishingReport_Response) ProtoMessage() {} | ||||
| func (*CCredentials_SteamGuardPhishingReport_Response) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{9} | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_SteamGuardPhishingReport_Response) GetIpaddressLoginattempt() uint32 { | ||||
| 	if m != nil && m.IpaddressLoginattempt != nil { | ||||
| 		return *m.IpaddressLoginattempt | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_SteamGuardPhishingReport_Response) GetCountrynameLoginattempt() string { | ||||
| 	if m != nil && m.CountrynameLoginattempt != nil { | ||||
| 		return *m.CountrynameLoginattempt | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_SteamGuardPhishingReport_Response) GetStatenameLoginattempt() string { | ||||
| 	if m != nil && m.StatenameLoginattempt != nil { | ||||
| 		return *m.StatenameLoginattempt | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_SteamGuardPhishingReport_Response) GetCitynameLoginattempt() string { | ||||
| 	if m != nil && m.CitynameLoginattempt != nil { | ||||
| 		return *m.CitynameLoginattempt | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_SteamGuardPhishingReport_Response) GetIpaddressActual() uint32 { | ||||
| 	if m != nil && m.IpaddressActual != nil { | ||||
| 		return *m.IpaddressActual | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_SteamGuardPhishingReport_Response) GetCountrynameActual() string { | ||||
| 	if m != nil && m.CountrynameActual != nil { | ||||
| 		return *m.CountrynameActual | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_SteamGuardPhishingReport_Response) GetStatenameActual() string { | ||||
| 	if m != nil && m.StatenameActual != nil { | ||||
| 		return *m.StatenameActual | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_SteamGuardPhishingReport_Response) GetCitynameActual() string { | ||||
| 	if m != nil && m.CitynameActual != nil { | ||||
| 		return *m.CitynameActual | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_SteamGuardPhishingReport_Response) GetSteamguardCode() string { | ||||
| 	if m != nil && m.SteamguardCode != nil { | ||||
| 		return *m.SteamguardCode | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| type CCredentials_AccountLockRequest_Request struct { | ||||
| 	ParamString      *string `protobuf:"bytes,1,opt,name=param_string" json:"param_string,omitempty"` | ||||
| 	IpaddressActual  *uint32 `protobuf:"varint,2,opt,name=ipaddress_actual" json:"ipaddress_actual,omitempty"` | ||||
| 	QueryOnly        *bool   `protobuf:"varint,3,opt,name=query_only" json:"query_only,omitempty"` | ||||
| 	EmailMessageType *int32  `protobuf:"varint,4,opt,name=email_message_type" json:"email_message_type,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_AccountLockRequest_Request) Reset() { | ||||
| 	*m = CCredentials_AccountLockRequest_Request{} | ||||
| } | ||||
| func (m *CCredentials_AccountLockRequest_Request) String() string { return proto.CompactTextString(m) } | ||||
| func (*CCredentials_AccountLockRequest_Request) ProtoMessage()    {} | ||||
| func (*CCredentials_AccountLockRequest_Request) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{10} | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_AccountLockRequest_Request) GetParamString() string { | ||||
| 	if m != nil && m.ParamString != nil { | ||||
| 		return *m.ParamString | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_AccountLockRequest_Request) GetIpaddressActual() uint32 { | ||||
| 	if m != nil && m.IpaddressActual != nil { | ||||
| 		return *m.IpaddressActual | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_AccountLockRequest_Request) GetQueryOnly() bool { | ||||
| 	if m != nil && m.QueryOnly != nil { | ||||
| 		return *m.QueryOnly | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_AccountLockRequest_Request) GetEmailMessageType() int32 { | ||||
| 	if m != nil && m.EmailMessageType != nil { | ||||
| 		return *m.EmailMessageType | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CCredentials_AccountLockRequest_Response struct { | ||||
| 	Success              *bool  `protobuf:"varint,1,opt,name=success" json:"success,omitempty"` | ||||
| 	AccountAlreadyLocked *bool  `protobuf:"varint,2,opt,name=account_already_locked" json:"account_already_locked,omitempty"` | ||||
| 	ExpiredLink          *bool  `protobuf:"varint,3,opt,name=expired_link" json:"expired_link,omitempty"` | ||||
| 	XXX_unrecognized     []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_AccountLockRequest_Response) Reset() { | ||||
| 	*m = CCredentials_AccountLockRequest_Response{} | ||||
| } | ||||
| func (m *CCredentials_AccountLockRequest_Response) String() string { return proto.CompactTextString(m) } | ||||
| func (*CCredentials_AccountLockRequest_Response) ProtoMessage()    {} | ||||
| func (*CCredentials_AccountLockRequest_Response) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{11} | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_AccountLockRequest_Response) GetSuccess() bool { | ||||
| 	if m != nil && m.Success != nil { | ||||
| 		return *m.Success | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_AccountLockRequest_Response) GetAccountAlreadyLocked() bool { | ||||
| 	if m != nil && m.AccountAlreadyLocked != nil { | ||||
| 		return *m.AccountAlreadyLocked | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_AccountLockRequest_Response) GetExpiredLink() bool { | ||||
| 	if m != nil && m.ExpiredLink != nil { | ||||
| 		return *m.ExpiredLink | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| type CCredentials_LastCredentialChangeTime_Request struct { | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_LastCredentialChangeTime_Request) Reset() { | ||||
| 	*m = CCredentials_LastCredentialChangeTime_Request{} | ||||
| } | ||||
| func (m *CCredentials_LastCredentialChangeTime_Request) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CCredentials_LastCredentialChangeTime_Request) ProtoMessage() {} | ||||
| func (*CCredentials_LastCredentialChangeTime_Request) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{12} | ||||
| } | ||||
|  | ||||
| type CCredentials_LastCredentialChangeTime_Response struct { | ||||
| 	TimestampLastPasswordChange *uint32 `protobuf:"fixed32,1,opt,name=timestamp_last_password_change" json:"timestamp_last_password_change,omitempty"` | ||||
| 	TimestampLastEmailChange    *uint32 `protobuf:"fixed32,2,opt,name=timestamp_last_email_change" json:"timestamp_last_email_change,omitempty"` | ||||
| 	TimestampLastPasswordReset  *uint32 `protobuf:"fixed32,3,opt,name=timestamp_last_password_reset" json:"timestamp_last_password_reset,omitempty"` | ||||
| 	XXX_unrecognized            []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_LastCredentialChangeTime_Response) Reset() { | ||||
| 	*m = CCredentials_LastCredentialChangeTime_Response{} | ||||
| } | ||||
| func (m *CCredentials_LastCredentialChangeTime_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CCredentials_LastCredentialChangeTime_Response) ProtoMessage() {} | ||||
| func (*CCredentials_LastCredentialChangeTime_Response) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{13} | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_LastCredentialChangeTime_Response) GetTimestampLastPasswordChange() uint32 { | ||||
| 	if m != nil && m.TimestampLastPasswordChange != nil { | ||||
| 		return *m.TimestampLastPasswordChange | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_LastCredentialChangeTime_Response) GetTimestampLastEmailChange() uint32 { | ||||
| 	if m != nil && m.TimestampLastEmailChange != nil { | ||||
| 		return *m.TimestampLastEmailChange | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_LastCredentialChangeTime_Response) GetTimestampLastPasswordReset() uint32 { | ||||
| 	if m != nil && m.TimestampLastPasswordReset != nil { | ||||
| 		return *m.TimestampLastPasswordReset | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CCredentials_GetAccountAuthSecret_Request struct { | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetAccountAuthSecret_Request) Reset() { | ||||
| 	*m = CCredentials_GetAccountAuthSecret_Request{} | ||||
| } | ||||
| func (m *CCredentials_GetAccountAuthSecret_Request) String() string { return proto.CompactTextString(m) } | ||||
| func (*CCredentials_GetAccountAuthSecret_Request) ProtoMessage()    {} | ||||
| func (*CCredentials_GetAccountAuthSecret_Request) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{14} | ||||
| } | ||||
|  | ||||
| type CCredentials_GetAccountAuthSecret_Response struct { | ||||
| 	SecretId         *int32 `protobuf:"varint,1,opt,name=secret_id" json:"secret_id,omitempty"` | ||||
| 	Secret           []byte `protobuf:"bytes,2,opt,name=secret" json:"secret,omitempty"` | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetAccountAuthSecret_Response) Reset() { | ||||
| 	*m = CCredentials_GetAccountAuthSecret_Response{} | ||||
| } | ||||
| func (m *CCredentials_GetAccountAuthSecret_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CCredentials_GetAccountAuthSecret_Response) ProtoMessage() {} | ||||
| func (*CCredentials_GetAccountAuthSecret_Response) Descriptor() ([]byte, []int) { | ||||
| 	return credentials_fileDescriptor0, []int{15} | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetAccountAuthSecret_Response) GetSecretId() int32 { | ||||
| 	if m != nil && m.SecretId != nil { | ||||
| 		return *m.SecretId | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CCredentials_GetAccountAuthSecret_Response) GetSecret() []byte { | ||||
| 	if m != nil { | ||||
| 		return m.Secret | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	proto.RegisterType((*CCredentials_TestAvailablePassword_Request)(nil), "CCredentials_TestAvailablePassword_Request") | ||||
| 	proto.RegisterType((*CCredentials_TestAvailablePassword_Response)(nil), "CCredentials_TestAvailablePassword_Response") | ||||
| 	proto.RegisterType((*CCredentials_GetSteamGuardDetails_Request)(nil), "CCredentials_GetSteamGuardDetails_Request") | ||||
| 	proto.RegisterType((*CCredentials_GetSteamGuardDetails_Response)(nil), "CCredentials_GetSteamGuardDetails_Response") | ||||
| 	proto.RegisterType((*CCredentials_GetSteamGuardDetails_Response_NewAuthentication)(nil), "CCredentials_GetSteamGuardDetails_Response.NewAuthentication") | ||||
| 	proto.RegisterType((*CCredentials_GetSteamGuardDetails_Response_SessionData)(nil), "CCredentials_GetSteamGuardDetails_Response.SessionData") | ||||
| 	proto.RegisterType((*CCredentials_NewMachineNotificationDialog_Request)(nil), "CCredentials_NewMachineNotificationDialog_Request") | ||||
| 	proto.RegisterType((*CCredentials_NewMachineNotificationDialog_Response)(nil), "CCredentials_NewMachineNotificationDialog_Response") | ||||
| 	proto.RegisterType((*CCredentials_ValidateEmailAddress_Request)(nil), "CCredentials_ValidateEmailAddress_Request") | ||||
| 	proto.RegisterType((*CCredentials_ValidateEmailAddress_Response)(nil), "CCredentials_ValidateEmailAddress_Response") | ||||
| 	proto.RegisterType((*CCredentials_SteamGuardPhishingReport_Request)(nil), "CCredentials_SteamGuardPhishingReport_Request") | ||||
| 	proto.RegisterType((*CCredentials_SteamGuardPhishingReport_Response)(nil), "CCredentials_SteamGuardPhishingReport_Response") | ||||
| 	proto.RegisterType((*CCredentials_AccountLockRequest_Request)(nil), "CCredentials_AccountLockRequest_Request") | ||||
| 	proto.RegisterType((*CCredentials_AccountLockRequest_Response)(nil), "CCredentials_AccountLockRequest_Response") | ||||
| 	proto.RegisterType((*CCredentials_LastCredentialChangeTime_Request)(nil), "CCredentials_LastCredentialChangeTime_Request") | ||||
| 	proto.RegisterType((*CCredentials_LastCredentialChangeTime_Response)(nil), "CCredentials_LastCredentialChangeTime_Response") | ||||
| 	proto.RegisterType((*CCredentials_GetAccountAuthSecret_Request)(nil), "CCredentials_GetAccountAuthSecret_Request") | ||||
| 	proto.RegisterType((*CCredentials_GetAccountAuthSecret_Response)(nil), "CCredentials_GetAccountAuthSecret_Response") | ||||
| } | ||||
|  | ||||
| var credentials_fileDescriptor0 = []byte{ | ||||
| 	// 1482 bytes of a gzipped FileDescriptorProto | ||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x57, 0x5d, 0x6f, 0x14, 0xd5, | ||||
| 	0x1b, 0xcf, 0x94, 0xbe, 0xec, 0x3e, 0xa5, 0x7f, 0xe8, 0x40, 0x61, 0x59, 0x0a, 0x4c, 0x06, 0xfe, | ||||
| 	0xb6, 0xd0, 0x3a, 0x48, 0x25, 0x41, 0x25, 0xc6, 0x94, 0x56, 0x09, 0x06, 0x90, 0x00, 0x51, 0xef, | ||||
| 	0x4e, 0x4e, 0x67, 0x4e, 0x77, 0x4f, 0x3a, 0x33, 0x67, 0x98, 0x39, 0xb3, 0x4b, 0x4d, 0x4c, 0xc4, | ||||
| 	0x3b, 0xbc, 0xf0, 0xce, 0x0b, 0x13, 0x2f, 0x8d, 0x5f, 0xc0, 0xe8, 0x17, 0xf0, 0x2b, 0xf8, 0x25, | ||||
| 	0xbc, 0x32, 0x7e, 0x03, 0x9f, 0x73, 0xe6, 0xec, 0xfb, 0x6c, 0xbb, 0x4b, 0xbc, 0xdc, 0x39, 0xcf, | ||||
| 	0xcb, 0xef, 0xf9, 0x3d, 0xaf, 0x0b, 0x1b, 0x99, 0x64, 0x34, 0x8a, 0x58, 0x96, 0xd1, 0x06, 0xcb, | ||||
| 	0x88, 0x9f, 0xb2, 0x80, 0xc5, 0x92, 0xd3, 0x30, 0xf3, 0xf4, 0x8b, 0x1f, 0x72, 0xfc, 0xed, 0x25, | ||||
| 	0xa9, 0x90, 0xa2, 0xbe, 0x39, 0x28, 0x9c, 0xc7, 0x7c, 0x9f, 0xb3, 0x80, 0xec, 0xd1, 0x8c, 0x8d, | ||||
| 	0x4a, 0xbb, 0x2f, 0xe0, 0xc6, 0xce, 0x4e, 0xcf, 0x1e, 0x79, 0xce, 0x32, 0xb9, 0xdd, 0xa2, 0x3c, | ||||
| 	0xa4, 0x7b, 0x21, 0x7b, 0x42, 0xb3, 0xac, 0x2d, 0xd2, 0x80, 0x3c, 0x65, 0x2f, 0x72, 0x7c, 0xb0, | ||||
| 	0x4f, 0x43, 0x25, 0x31, 0xdf, 0x6a, 0x96, 0x63, 0xad, 0x57, 0xed, 0x8b, 0x70, 0x26, 0x6b, 0x52, | ||||
| 	0x12, 0x70, 0xf4, 0x25, 0x49, 0xf7, 0x71, 0x06, 0x1f, 0x4f, 0xda, 0x67, 0xe1, 0x24, 0xf5, 0x7d, | ||||
| 	0x91, 0xc7, 0x92, 0xc4, 0x34, 0x62, 0xb5, 0x13, 0x4a, 0xc5, 0xfd, 0x08, 0x36, 0x26, 0x72, 0x99, | ||||
| 	0x25, 0x22, 0xce, 0x98, 0xf2, 0xc9, 0x33, 0xd2, 0xa2, 0x21, 0x0f, 0xb4, 0x81, 0x8a, 0xfb, 0xf7, | ||||
| 	0x0c, 0x5c, 0x1f, 0xb0, 0x70, 0x9f, 0xc9, 0x67, 0x2a, 0xb2, 0xfb, 0x39, 0x4d, 0x83, 0x5d, 0x26, | ||||
| 	0xd1, 0x56, 0xd6, 0xc5, 0x9c, 0xc3, 0x45, 0x1e, 0xfb, 0x61, 0x1e, 0x30, 0x12, 0xb3, 0x36, 0xa1, | ||||
| 	0xb9, 0x6c, 0x2a, 0x3d, 0x9f, 0x4a, 0x8e, 0xf6, 0x75, 0x18, 0x95, 0x0f, 0x66, 0x65, 0x9a, 0xb3, | ||||
| 	0x7b, 0x9f, 0x7e, 0xfb, 0x5b, 0xed, 0x93, 0x2f, 0x9a, 0x0c, 0x25, 0x52, 0x47, 0xa4, 0x4e, 0x2c, | ||||
| 	0xa4, 0x23, 0x85, 0x93, 0x88, 0x24, 0x0f, 0xa9, 0x64, 0x0e, 0x7e, 0x77, 0xd0, 0xc6, 0xa0, 0x09, | ||||
| 	0x07, 0xe9, 0x0d, 0x03, 0x87, 0xc7, 0xfa, 0x39, 0xed, 0xc0, 0xfe, 0xc1, 0x82, 0x6a, 0x9b, 0xed, | ||||
| 	0xf9, 0x42, 0x1c, 0x70, 0xa6, 0xf9, 0xa8, 0xde, 0x7b, 0x65, 0xa1, 0x83, 0xaf, 0x9f, 0xa3, 0x58, | ||||
| 	0x9e, 0xb1, 0x74, 0x2d, 0x73, 0x34, 0x6a, 0x47, 0xc3, 0x76, 0x22, 0xea, 0x37, 0x79, 0xcc, 0x1c, | ||||
| 	0x65, 0xdd, 0x29, 0xd4, 0x3c, 0xe7, 0xc1, 0xbe, 0x93, 0xa0, 0x49, 0xf4, 0xb6, 0xe9, 0x70, 0xb9, | ||||
| 	0x16, 0x86, 0xce, 0x9e, 0x56, 0x0e, 0x14, 0xae, 0x06, 0x93, 0xda, 0xa7, 0x31, 0xd6, 0x31, 0xf0, | ||||
| 	0x60, 0x17, 0xc1, 0xa8, 0x4c, 0x07, 0x8e, 0xd8, 0xd7, 0x02, 0xdb, 0x8f, 0x9c, 0x0c, 0xeb, 0x01, | ||||
| 	0xc1, 0x7a, 0xb6, 0x03, 0x35, 0xc9, 0xb1, 0x3a, 0x24, 0x8d, 0x12, 0x12, 0xf1, 0x98, 0x47, 0x79, | ||||
| 	0x44, 0xda, 0x34, 0x96, 0xac, 0xa0, 0x77, 0xc1, 0x5e, 0x86, 0x2a, 0x4f, 0x68, 0x10, 0xa0, 0xdf, | ||||
| 	0xac, 0x36, 0x8b, 0x9f, 0xe6, 0xdc, 0xbf, 0x2a, 0x43, 0x65, 0x32, 0x86, 0x71, 0x13, 0xfb, 0x25, | ||||
| 	0x58, 0xc1, 0x94, 0xe9, 0x62, 0x6b, 0x28, 0x01, 0xc2, 0x62, 0x95, 0xdb, 0xa2, 0x66, 0x2a, 0xf6, | ||||
| 	0x35, 0x58, 0xed, 0x41, 0x28, 0x91, 0x9a, 0xd1, 0x30, 0x7c, 0x58, 0x0d, 0x18, 0x06, 0x8f, 0x2c, | ||||
| 	0x63, 0xf9, 0x8e, 0xd0, 0x8e, 0x60, 0x4f, 0xac, 0x2f, 0x6e, 0x7d, 0xe8, 0x4d, 0x8e, 0xcb, 0x7b, | ||||
| 	0xcc, 0xda, 0xdb, 0x03, 0x46, 0xec, 0x1b, 0xe0, 0xf6, 0x39, 0x31, 0x0c, 0xea, 0x62, 0x25, 0x8a, | ||||
| 	0x55, 0xbf, 0x29, 0x90, 0x7b, 0x4d, 0x42, 0xd5, 0xbe, 0x03, 0x37, 0xfb, 0x64, 0xfb, 0x48, 0x34, | ||||
| 	0x5a, 0x25, 0x91, 0xcc, 0xe9, 0x48, 0x76, 0xe0, 0x6e, 0x9f, 0xe2, 0x60, 0x18, 0x84, 0xbd, 0xe4, | ||||
| 	0x99, 0xcc, 0xc8, 0x7e, 0x2a, 0x22, 0xd2, 0x60, 0x22, 0x14, 0x3e, 0xd9, 0x63, 0xfb, 0x22, 0x65, | ||||
| 	0x2a, 0x39, 0xca, 0x49, 0x6d, 0x5e, 0x93, 0x86, 0x9c, 0x96, 0x20, 0xc5, 0x9e, 0x58, 0xc0, 0xe7, | ||||
| 	0x59, 0xfb, 0x11, 0x9c, 0x34, 0x29, 0x26, 0x01, 0x95, 0xb4, 0x56, 0xd1, 0xec, 0xdc, 0x99, 0x86, | ||||
| 	0x9d, 0x67, 0x85, 0xfe, 0x2e, 0xaa, 0xdb, 0xab, 0x70, 0x16, 0x33, 0x28, 0xdb, 0x62, 0x9f, 0xfa, | ||||
| 	0x52, 0xa4, 0xdd, 0x80, 0xaa, 0x1a, 0xcb, 0x55, 0xb8, 0xd8, 0x0b, 0x7f, 0x54, 0x08, 0x74, 0xd4, | ||||
| 	0x17, 0x60, 0x19, 0x4d, 0x24, 0x4d, 0x81, 0x30, 0x5b, 0x2c, 0xd5, 0x53, 0xa8, 0xb6, 0xa8, 0xf4, | ||||
| 	0xeb, 0x7f, 0x58, 0xb0, 0x3c, 0x9a, 0x8b, 0xe3, 0xca, 0xc2, 0xd2, 0x66, 0x57, 0x60, 0x09, 0xcd, | ||||
| 	0x62, 0x67, 0x91, 0xbe, 0xd6, 0xaa, 0x0c, 0x16, 0xad, 0xaa, 0xe3, 0x39, 0xfb, 0x0c, 0x2c, 0x1a, | ||||
| 	0x42, 0x79, 0xbc, 0x2f, 0x4c, 0x12, 0x0b, 0xf5, 0x94, 0x45, 0x2c, 0xda, 0x63, 0xa9, 0x49, 0x51, | ||||
| 	0xc5, 0x76, 0xa1, 0x3e, 0x92, 0x7c, 0x92, 0xe5, 0x49, 0x12, 0x2a, 0xd4, 0xf3, 0x5a, 0xf5, 0x7f, | ||||
| 	0x30, 0x8f, 0xd8, 0x64, 0x9e, 0x69, 0xca, 0xe7, 0xea, 0x7f, 0xce, 0xc0, 0x62, 0x3f, 0x67, 0x36, | ||||
| 	0x40, 0x5f, 0x5a, 0x2c, 0x9d, 0x96, 0x2b, 0x70, 0x7e, 0x5c, 0x51, 0xe9, 0x91, 0x60, 0x6f, 0xc2, | ||||
| 	0xb5, 0x89, 0x2a, 0xa9, 0x68, 0xcd, 0xf7, 0xe0, 0x9d, 0xa9, 0xcb, 0x67, 0x56, 0x07, 0xf8, 0x25, | ||||
| 	0x2c, 0x8f, 0xb6, 0xd0, 0xdc, 0x7f, 0xd1, 0x42, 0xef, 0xc3, 0xad, 0x23, 0x30, 0x65, 0x2a, 0x6a, | ||||
| 	0x9e, 0x94, 0xd7, 0x34, 0x66, 0x28, 0xc9, 0xf7, 0x42, 0x8e, 0x19, 0x4a, 0x5a, 0xb7, 0x35, 0xad, | ||||
| 	0x4b, 0x6e, 0x00, 0xb7, 0x06, 0xf0, 0xa0, 0xc7, 0x47, 0x05, 0x2f, 0x8f, 0x85, 0xc4, 0x2a, 0x2a, | ||||
| 	0x9c, 0xec, 0xe2, 0x9b, 0x68, 0x74, 0x87, 0x3c, 0x5a, 0xc2, 0xb4, 0xd2, 0x04, 0x97, 0x5a, 0xab, | ||||
| 	0x3b, 0x67, 0xea, 0x60, 0xab, 0x52, 0xe1, 0x5f, 0x29, 0x22, 0x7d, 0x11, 0x25, 0x21, 0x93, 0xa6, | ||||
| 	0x5e, 0xdc, 0xdb, 0xb0, 0x35, 0x8d, 0x97, 0x22, 0x7a, 0xf7, 0xee, 0xd0, 0xe2, 0xf9, 0x5c, 0x6d, | ||||
| 	0x25, 0x6c, 0xc8, 0x8f, 0x23, 0x64, 0x69, 0xbb, 0xa8, 0xbe, 0x2e, 0x26, 0x5d, 0x2f, 0xe2, 0x00, | ||||
| 	0x53, 0xad, 0x57, 0xa5, 0xbb, 0x33, 0x34, 0x43, 0xc7, 0x28, 0x9b, 0x19, 0x8a, 0x85, 0xda, 0xa6, | ||||
| 	0x66, 0xef, 0xa9, 0x96, 0x2f, 0x62, 0x72, 0x09, 0xbc, 0x3d, 0x60, 0xa4, 0x97, 0xaa, 0x27, 0x4d, | ||||
| 	0x9e, 0x21, 0xfe, 0xc6, 0x53, 0x96, 0x88, 0x54, 0x76, 0x51, 0xe0, 0x0e, 0x4e, 0x68, 0x4a, 0x31, | ||||
| 	0x13, 0x32, 0xc5, 0x57, 0xb3, 0xb6, 0x6b, 0x70, 0xba, 0xdb, 0x2e, 0x04, 0xbb, 0x37, 0xa7, 0xa1, | ||||
| 	0x26, 0x66, 0xc9, 0xfd, 0x75, 0x06, 0xbc, 0x49, 0x3d, 0x18, 0xa8, 0x97, 0xe1, 0x5c, 0xcf, 0x18, | ||||
| 	0xf2, 0xc5, 0x63, 0x2a, 0x25, 0x8b, 0x12, 0xa9, 0x9d, 0x2d, 0xa9, 0x95, 0xa3, 0x8f, 0x80, 0xf4, | ||||
| 	0x50, 0xf7, 0xc0, 0x80, 0x44, 0xd1, 0x05, 0x68, 0x41, 0xb5, 0x16, 0x1b, 0x7d, 0xd7, 0x27, 0x83, | ||||
| 	0x1a, 0x7e, 0x3e, 0x97, 0x25, 0xea, 0xb3, 0x63, 0xa3, 0x99, 0xd3, 0xae, 0xb1, 0x04, 0xfa, 0x5d, | ||||
| 	0x9b, 0xb7, 0xf9, 0x8e, 0x56, 0xcf, 0xa9, 0x79, 0x59, 0xd0, 0x2f, 0xe7, 0xe1, 0x54, 0xd7, 0x9d, | ||||
| 	0x79, 0xa8, 0x74, 0x1e, 0xfa, 0x7a, 0xd3, 0x17, 0x01, 0xd3, 0x13, 0xb1, 0xea, 0xbe, 0xb6, 0x60, | ||||
| 	0x6d, 0x80, 0xb5, 0xed, 0xe2, 0xee, 0x79, 0x28, 0xfc, 0x03, 0x93, 0x89, 0x37, 0xcd, 0x88, 0x9a, | ||||
| 	0x2b, 0xa8, 0x98, 0x1e, 0x12, 0x11, 0x87, 0x87, 0xc5, 0x09, 0xa4, 0xe2, 0x62, 0xaa, 0x6c, 0x88, | ||||
| 	0xb9, 0xf3, 0x88, 0x3c, 0x4c, 0x98, 0x59, 0xd6, 0x2f, 0x60, 0xfd, 0x78, 0x28, 0x26, 0x75, 0xa7, | ||||
| 	0x60, 0x21, 0xcb, 0x7d, 0x5f, 0x0d, 0xcd, 0xa2, 0x67, 0x30, 0x13, 0x9d, 0x93, 0x8d, 0x86, 0x29, | ||||
| 	0xde, 0x10, 0x87, 0x48, 0xb8, 0x7f, 0x60, 0xb6, 0x72, 0x45, 0x81, 0x67, 0x2f, 0x13, 0x8e, 0xe6, | ||||
| 	0x49, 0xc8, 0xe3, 0x03, 0x73, 0x91, 0xdd, 0x1c, 0xaa, 0xca, 0x87, 0x34, 0x93, 0xbd, 0xdf, 0x3b, | ||||
| 	0x4d, 0x1a, 0x37, 0xd8, 0x73, 0xec, 0xfb, 0x0e, 0x07, 0xee, 0xcf, 0xd6, 0x50, 0x95, 0x1d, 0xa1, | ||||
| 	0x61, 0xa0, 0xbe, 0x05, 0x97, 0x7b, 0x93, 0x32, 0xa4, 0x7d, 0xd7, 0x26, 0xf1, 0xb5, 0xb8, 0x59, | ||||
| 	0x10, 0x03, 0xcb, 0x49, 0xcb, 0x15, 0x4c, 0x19, 0xa1, 0xe2, 0xb8, 0xf8, 0x3f, 0x5c, 0x1a, 0x67, | ||||
| 	0x4c, 0x9d, 0x5b, 0x45, 0xdd, 0x2d, 0xb8, 0x1b, 0xa3, 0x87, 0xa6, 0x61, 0x53, 0x0d, 0xc1, 0x67, | ||||
| 	0x0c, 0x2f, 0xf1, 0x6e, 0x5e, 0xdd, 0xcf, 0x46, 0x6f, 0xa4, 0x32, 0x61, 0x13, 0x0e, 0x2e, 0xac, | ||||
| 	0xac, 0xf8, 0x64, 0x96, 0xc5, 0x9c, 0x1e, 0x18, 0xfa, 0x53, 0x71, 0x3e, 0x6f, 0xfd, 0x53, 0x85, | ||||
| 	0xc5, 0x3e, 0x83, 0xf6, 0xf7, 0x16, 0xac, 0x94, 0x1e, 0xcb, 0xf6, 0x86, 0x37, 0xf9, 0x11, 0x5f, | ||||
| 	0xdf, 0xf4, 0xa6, 0x38, 0xbf, 0xdd, 0x3a, 0x9e, 0xac, 0xe7, 0x4a, 0x65, 0x3c, 0xfb, 0x3b, 0x0b, | ||||
| 	0xce, 0x96, 0xad, 0x0b, 0xfb, 0x86, 0x37, 0xf1, 0x7d, 0x5e, 0xdf, 0x98, 0x62, 0xfd, 0xb8, 0x17, | ||||
| 	0x10, 0xcd, 0x4a, 0x99, 0x88, 0x67, 0xff, 0x6e, 0x81, 0x7b, 0xd4, 0x14, 0x47, 0x1b, 0x79, 0x28, | ||||
| 	0xed, 0x2d, 0x6f, 0xea, 0xed, 0x52, 0x7f, 0xd7, 0x7b, 0x83, 0x5d, 0xb1, 0x86, 0x50, 0xaf, 0x1e, | ||||
| 	0x0f, 0xc8, 0xb3, 0x7f, 0x42, 0x16, 0xcb, 0x76, 0xc1, 0x30, 0x8b, 0x47, 0x2d, 0x9b, 0x61, 0x16, | ||||
| 	0x8f, 0xdc, 0x2d, 0xee, 0x06, 0x42, 0x5b, 0xeb, 0x88, 0x38, 0x34, 0x76, 0x74, 0x87, 0x38, 0x66, | ||||
| 	0xfa, 0x38, 0x0d, 0xde, 0x62, 0xb1, 0x43, 0x1d, 0xbd, 0xbc, 0xec, 0x1f, 0x2d, 0xa8, 0x8d, 0xdb, | ||||
| 	0x01, 0xb6, 0xe7, 0x4d, 0xb5, 0x8d, 0xea, 0x37, 0xa7, 0xdc, 0x2d, 0xee, 0x2a, 0x42, 0x1d, 0xef, | ||||
| 	0xfe, 0x95, 0x05, 0xf6, 0xe8, 0x78, 0xb3, 0xd7, 0xbd, 0x09, 0x67, 0x71, 0xfd, 0xba, 0x37, 0xe9, | ||||
| 	0xa8, 0x74, 0xcf, 0x21, 0x92, 0x32, 0x67, 0xbf, 0x58, 0x70, 0x19, 0x2b, 0xb2, 0x6c, 0x78, 0x75, | ||||
| 	0xda, 0xc1, 0xf3, 0xa6, 0x9a, 0x8e, 0xc3, 0x2c, 0x1d, 0x3b, 0x1b, 0xdd, 0xab, 0x88, 0xed, 0xca, | ||||
| 	0xd1, 0x20, 0x3c, 0xfb, 0x75, 0xd1, 0xad, 0x23, 0x33, 0xa9, 0xa4, 0x5b, 0xc7, 0x0e, 0xb9, 0x92, | ||||
| 	0x6e, 0x1d, 0x3f, 0xe3, 0xdc, 0x1a, 0xc2, 0x2a, 0x75, 0x59, 0x3f, 0x8f, 0x2f, 0x67, 0xfa, 0x0c, | ||||
| 	0xe1, 0xff, 0xd3, 0xb4, 0xc5, 0x7d, 0x76, 0xef, 0xc4, 0x37, 0x96, 0xf5, 0x6f, 0x00, 0x00, 0x00, | ||||
| 	0xff, 0xff, 0x3c, 0x6e, 0x05, 0xde, 0xf0, 0x10, 0x00, 0x00, | ||||
| } | ||||
							
								
								
									
										694
									
								
								vendor/github.com/Philipp15b/go-steam/protocol/protobuf/unified/deviceauth.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										694
									
								
								vendor/github.com/Philipp15b/go-steam/protocol/protobuf/unified/deviceauth.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,694 +0,0 @@ | ||||
| // Code generated by protoc-gen-go. | ||||
| // source: steammessages_deviceauth.steamclient.proto | ||||
| // DO NOT EDIT! | ||||
|  | ||||
| package unified | ||||
|  | ||||
| import proto "github.com/golang/protobuf/proto" | ||||
| import fmt "fmt" | ||||
| import math "math" | ||||
|  | ||||
| // Reference imports to suppress errors if they are not otherwise used. | ||||
| var _ = proto.Marshal | ||||
| var _ = fmt.Errorf | ||||
| var _ = math.Inf | ||||
|  | ||||
| type CDeviceAuth_GetOwnAuthorizedDevices_Request struct { | ||||
| 	Steamid          *uint64 `protobuf:"fixed64,1,opt,name=steamid" json:"steamid,omitempty"` | ||||
| 	IncludeCanceled  *bool   `protobuf:"varint,2,opt,name=include_canceled" json:"include_canceled,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Request) Reset() { | ||||
| 	*m = CDeviceAuth_GetOwnAuthorizedDevices_Request{} | ||||
| } | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Request) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_GetOwnAuthorizedDevices_Request) ProtoMessage() {} | ||||
| func (*CDeviceAuth_GetOwnAuthorizedDevices_Request) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{0} | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Request) GetSteamid() uint64 { | ||||
| 	if m != nil && m.Steamid != nil { | ||||
| 		return *m.Steamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Request) GetIncludeCanceled() bool { | ||||
| 	if m != nil && m.IncludeCanceled != nil { | ||||
| 		return *m.IncludeCanceled | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_GetOwnAuthorizedDevices_Response struct { | ||||
| 	Devices          []*CDeviceAuth_GetOwnAuthorizedDevices_Response_Device `protobuf:"bytes,1,rep,name=devices" json:"devices,omitempty"` | ||||
| 	XXX_unrecognized []byte                                                 `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Response) Reset() { | ||||
| 	*m = CDeviceAuth_GetOwnAuthorizedDevices_Response{} | ||||
| } | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_GetOwnAuthorizedDevices_Response) ProtoMessage() {} | ||||
| func (*CDeviceAuth_GetOwnAuthorizedDevices_Response) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{1} | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Response) GetDevices() []*CDeviceAuth_GetOwnAuthorizedDevices_Response_Device { | ||||
| 	if m != nil { | ||||
| 		return m.Devices | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_GetOwnAuthorizedDevices_Response_Device struct { | ||||
| 	AuthDeviceToken  *uint64 `protobuf:"fixed64,1,opt,name=auth_device_token" json:"auth_device_token,omitempty"` | ||||
| 	DeviceName       *string `protobuf:"bytes,2,opt,name=device_name" json:"device_name,omitempty"` | ||||
| 	IsPending        *bool   `protobuf:"varint,3,opt,name=is_pending" json:"is_pending,omitempty"` | ||||
| 	IsCanceled       *bool   `protobuf:"varint,4,opt,name=is_canceled" json:"is_canceled,omitempty"` | ||||
| 	LastTimeUsed     *uint32 `protobuf:"varint,5,opt,name=last_time_used" json:"last_time_used,omitempty"` | ||||
| 	LastBorrowerId   *uint64 `protobuf:"fixed64,6,opt,name=last_borrower_id" json:"last_borrower_id,omitempty"` | ||||
| 	LastAppPlayed    *uint32 `protobuf:"varint,7,opt,name=last_app_played" json:"last_app_played,omitempty"` | ||||
| 	IsLimited        *bool   `protobuf:"varint,8,opt,name=is_limited" json:"is_limited,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Response_Device) Reset() { | ||||
| 	*m = CDeviceAuth_GetOwnAuthorizedDevices_Response_Device{} | ||||
| } | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Response_Device) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_GetOwnAuthorizedDevices_Response_Device) ProtoMessage() {} | ||||
| func (*CDeviceAuth_GetOwnAuthorizedDevices_Response_Device) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{1, 0} | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Response_Device) GetAuthDeviceToken() uint64 { | ||||
| 	if m != nil && m.AuthDeviceToken != nil { | ||||
| 		return *m.AuthDeviceToken | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Response_Device) GetDeviceName() string { | ||||
| 	if m != nil && m.DeviceName != nil { | ||||
| 		return *m.DeviceName | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Response_Device) GetIsPending() bool { | ||||
| 	if m != nil && m.IsPending != nil { | ||||
| 		return *m.IsPending | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Response_Device) GetIsCanceled() bool { | ||||
| 	if m != nil && m.IsCanceled != nil { | ||||
| 		return *m.IsCanceled | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Response_Device) GetLastTimeUsed() uint32 { | ||||
| 	if m != nil && m.LastTimeUsed != nil { | ||||
| 		return *m.LastTimeUsed | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Response_Device) GetLastBorrowerId() uint64 { | ||||
| 	if m != nil && m.LastBorrowerId != nil { | ||||
| 		return *m.LastBorrowerId | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Response_Device) GetLastAppPlayed() uint32 { | ||||
| 	if m != nil && m.LastAppPlayed != nil { | ||||
| 		return *m.LastAppPlayed | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetOwnAuthorizedDevices_Response_Device) GetIsLimited() bool { | ||||
| 	if m != nil && m.IsLimited != nil { | ||||
| 		return *m.IsLimited | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_AcceptAuthorizationRequest_Request struct { | ||||
| 	Steamid          *uint64 `protobuf:"fixed64,1,opt,name=steamid" json:"steamid,omitempty"` | ||||
| 	AuthDeviceToken  *uint64 `protobuf:"fixed64,2,opt,name=auth_device_token" json:"auth_device_token,omitempty"` | ||||
| 	AuthCode         *uint64 `protobuf:"fixed64,3,opt,name=auth_code" json:"auth_code,omitempty"` | ||||
| 	FromSteamid      *uint64 `protobuf:"fixed64,4,opt,name=from_steamid" json:"from_steamid,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_AcceptAuthorizationRequest_Request) Reset() { | ||||
| 	*m = CDeviceAuth_AcceptAuthorizationRequest_Request{} | ||||
| } | ||||
| func (m *CDeviceAuth_AcceptAuthorizationRequest_Request) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_AcceptAuthorizationRequest_Request) ProtoMessage() {} | ||||
| func (*CDeviceAuth_AcceptAuthorizationRequest_Request) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{2} | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_AcceptAuthorizationRequest_Request) GetSteamid() uint64 { | ||||
| 	if m != nil && m.Steamid != nil { | ||||
| 		return *m.Steamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_AcceptAuthorizationRequest_Request) GetAuthDeviceToken() uint64 { | ||||
| 	if m != nil && m.AuthDeviceToken != nil { | ||||
| 		return *m.AuthDeviceToken | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_AcceptAuthorizationRequest_Request) GetAuthCode() uint64 { | ||||
| 	if m != nil && m.AuthCode != nil { | ||||
| 		return *m.AuthCode | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_AcceptAuthorizationRequest_Request) GetFromSteamid() uint64 { | ||||
| 	if m != nil && m.FromSteamid != nil { | ||||
| 		return *m.FromSteamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_AcceptAuthorizationRequest_Response struct { | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_AcceptAuthorizationRequest_Response) Reset() { | ||||
| 	*m = CDeviceAuth_AcceptAuthorizationRequest_Response{} | ||||
| } | ||||
| func (m *CDeviceAuth_AcceptAuthorizationRequest_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_AcceptAuthorizationRequest_Response) ProtoMessage() {} | ||||
| func (*CDeviceAuth_AcceptAuthorizationRequest_Response) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{3} | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_AuthorizeRemoteDevice_Request struct { | ||||
| 	Steamid          *uint64 `protobuf:"fixed64,1,opt,name=steamid" json:"steamid,omitempty"` | ||||
| 	AuthDeviceToken  *uint64 `protobuf:"fixed64,2,opt,name=auth_device_token" json:"auth_device_token,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_AuthorizeRemoteDevice_Request) Reset() { | ||||
| 	*m = CDeviceAuth_AuthorizeRemoteDevice_Request{} | ||||
| } | ||||
| func (m *CDeviceAuth_AuthorizeRemoteDevice_Request) String() string { return proto.CompactTextString(m) } | ||||
| func (*CDeviceAuth_AuthorizeRemoteDevice_Request) ProtoMessage()    {} | ||||
| func (*CDeviceAuth_AuthorizeRemoteDevice_Request) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{4} | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_AuthorizeRemoteDevice_Request) GetSteamid() uint64 { | ||||
| 	if m != nil && m.Steamid != nil { | ||||
| 		return *m.Steamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_AuthorizeRemoteDevice_Request) GetAuthDeviceToken() uint64 { | ||||
| 	if m != nil && m.AuthDeviceToken != nil { | ||||
| 		return *m.AuthDeviceToken | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_AuthorizeRemoteDevice_Response struct { | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_AuthorizeRemoteDevice_Response) Reset() { | ||||
| 	*m = CDeviceAuth_AuthorizeRemoteDevice_Response{} | ||||
| } | ||||
| func (m *CDeviceAuth_AuthorizeRemoteDevice_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_AuthorizeRemoteDevice_Response) ProtoMessage() {} | ||||
| func (*CDeviceAuth_AuthorizeRemoteDevice_Response) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{5} | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_DeauthorizeRemoteDevice_Request struct { | ||||
| 	Steamid          *uint64 `protobuf:"fixed64,1,opt,name=steamid" json:"steamid,omitempty"` | ||||
| 	AuthDeviceToken  *uint64 `protobuf:"fixed64,2,opt,name=auth_device_token" json:"auth_device_token,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_DeauthorizeRemoteDevice_Request) Reset() { | ||||
| 	*m = CDeviceAuth_DeauthorizeRemoteDevice_Request{} | ||||
| } | ||||
| func (m *CDeviceAuth_DeauthorizeRemoteDevice_Request) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_DeauthorizeRemoteDevice_Request) ProtoMessage() {} | ||||
| func (*CDeviceAuth_DeauthorizeRemoteDevice_Request) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{6} | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_DeauthorizeRemoteDevice_Request) GetSteamid() uint64 { | ||||
| 	if m != nil && m.Steamid != nil { | ||||
| 		return *m.Steamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_DeauthorizeRemoteDevice_Request) GetAuthDeviceToken() uint64 { | ||||
| 	if m != nil && m.AuthDeviceToken != nil { | ||||
| 		return *m.AuthDeviceToken | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_DeauthorizeRemoteDevice_Response struct { | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_DeauthorizeRemoteDevice_Response) Reset() { | ||||
| 	*m = CDeviceAuth_DeauthorizeRemoteDevice_Response{} | ||||
| } | ||||
| func (m *CDeviceAuth_DeauthorizeRemoteDevice_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_DeauthorizeRemoteDevice_Response) ProtoMessage() {} | ||||
| func (*CDeviceAuth_DeauthorizeRemoteDevice_Response) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{7} | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_GetUsedAuthorizedDevices_Request struct { | ||||
| 	Steamid          *uint64 `protobuf:"fixed64,1,opt,name=steamid" json:"steamid,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetUsedAuthorizedDevices_Request) Reset() { | ||||
| 	*m = CDeviceAuth_GetUsedAuthorizedDevices_Request{} | ||||
| } | ||||
| func (m *CDeviceAuth_GetUsedAuthorizedDevices_Request) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_GetUsedAuthorizedDevices_Request) ProtoMessage() {} | ||||
| func (*CDeviceAuth_GetUsedAuthorizedDevices_Request) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{8} | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetUsedAuthorizedDevices_Request) GetSteamid() uint64 { | ||||
| 	if m != nil && m.Steamid != nil { | ||||
| 		return *m.Steamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_GetUsedAuthorizedDevices_Response struct { | ||||
| 	Devices          []*CDeviceAuth_GetUsedAuthorizedDevices_Response_Device `protobuf:"bytes,1,rep,name=devices" json:"devices,omitempty"` | ||||
| 	XXX_unrecognized []byte                                                  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetUsedAuthorizedDevices_Response) Reset() { | ||||
| 	*m = CDeviceAuth_GetUsedAuthorizedDevices_Response{} | ||||
| } | ||||
| func (m *CDeviceAuth_GetUsedAuthorizedDevices_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_GetUsedAuthorizedDevices_Response) ProtoMessage() {} | ||||
| func (*CDeviceAuth_GetUsedAuthorizedDevices_Response) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{9} | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetUsedAuthorizedDevices_Response) GetDevices() []*CDeviceAuth_GetUsedAuthorizedDevices_Response_Device { | ||||
| 	if m != nil { | ||||
| 		return m.Devices | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_GetUsedAuthorizedDevices_Response_Device struct { | ||||
| 	AuthDeviceToken  *uint64 `protobuf:"fixed64,1,opt,name=auth_device_token" json:"auth_device_token,omitempty"` | ||||
| 	DeviceName       *string `protobuf:"bytes,2,opt,name=device_name" json:"device_name,omitempty"` | ||||
| 	OwnerSteamid     *uint64 `protobuf:"fixed64,3,opt,name=owner_steamid" json:"owner_steamid,omitempty"` | ||||
| 	LastTimeUsed     *uint32 `protobuf:"varint,4,opt,name=last_time_used" json:"last_time_used,omitempty"` | ||||
| 	LastAppPlayed    *uint32 `protobuf:"varint,5,opt,name=last_app_played" json:"last_app_played,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetUsedAuthorizedDevices_Response_Device) Reset() { | ||||
| 	*m = CDeviceAuth_GetUsedAuthorizedDevices_Response_Device{} | ||||
| } | ||||
| func (m *CDeviceAuth_GetUsedAuthorizedDevices_Response_Device) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_GetUsedAuthorizedDevices_Response_Device) ProtoMessage() {} | ||||
| func (*CDeviceAuth_GetUsedAuthorizedDevices_Response_Device) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{9, 0} | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetUsedAuthorizedDevices_Response_Device) GetAuthDeviceToken() uint64 { | ||||
| 	if m != nil && m.AuthDeviceToken != nil { | ||||
| 		return *m.AuthDeviceToken | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetUsedAuthorizedDevices_Response_Device) GetDeviceName() string { | ||||
| 	if m != nil && m.DeviceName != nil { | ||||
| 		return *m.DeviceName | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetUsedAuthorizedDevices_Response_Device) GetOwnerSteamid() uint64 { | ||||
| 	if m != nil && m.OwnerSteamid != nil { | ||||
| 		return *m.OwnerSteamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetUsedAuthorizedDevices_Response_Device) GetLastTimeUsed() uint32 { | ||||
| 	if m != nil && m.LastTimeUsed != nil { | ||||
| 		return *m.LastTimeUsed | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetUsedAuthorizedDevices_Response_Device) GetLastAppPlayed() uint32 { | ||||
| 	if m != nil && m.LastAppPlayed != nil { | ||||
| 		return *m.LastAppPlayed | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_GetAuthorizedBorrowers_Request struct { | ||||
| 	Steamid          *uint64 `protobuf:"fixed64,1,opt,name=steamid" json:"steamid,omitempty"` | ||||
| 	IncludeCanceled  *bool   `protobuf:"varint,2,opt,name=include_canceled" json:"include_canceled,omitempty"` | ||||
| 	IncludePending   *bool   `protobuf:"varint,3,opt,name=include_pending" json:"include_pending,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetAuthorizedBorrowers_Request) Reset() { | ||||
| 	*m = CDeviceAuth_GetAuthorizedBorrowers_Request{} | ||||
| } | ||||
| func (m *CDeviceAuth_GetAuthorizedBorrowers_Request) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_GetAuthorizedBorrowers_Request) ProtoMessage() {} | ||||
| func (*CDeviceAuth_GetAuthorizedBorrowers_Request) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{10} | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetAuthorizedBorrowers_Request) GetSteamid() uint64 { | ||||
| 	if m != nil && m.Steamid != nil { | ||||
| 		return *m.Steamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetAuthorizedBorrowers_Request) GetIncludeCanceled() bool { | ||||
| 	if m != nil && m.IncludeCanceled != nil { | ||||
| 		return *m.IncludeCanceled | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetAuthorizedBorrowers_Request) GetIncludePending() bool { | ||||
| 	if m != nil && m.IncludePending != nil { | ||||
| 		return *m.IncludePending | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_GetAuthorizedBorrowers_Response struct { | ||||
| 	Borrowers        []*CDeviceAuth_GetAuthorizedBorrowers_Response_Borrower `protobuf:"bytes,1,rep,name=borrowers" json:"borrowers,omitempty"` | ||||
| 	XXX_unrecognized []byte                                                  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetAuthorizedBorrowers_Response) Reset() { | ||||
| 	*m = CDeviceAuth_GetAuthorizedBorrowers_Response{} | ||||
| } | ||||
| func (m *CDeviceAuth_GetAuthorizedBorrowers_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_GetAuthorizedBorrowers_Response) ProtoMessage() {} | ||||
| func (*CDeviceAuth_GetAuthorizedBorrowers_Response) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{11} | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetAuthorizedBorrowers_Response) GetBorrowers() []*CDeviceAuth_GetAuthorizedBorrowers_Response_Borrower { | ||||
| 	if m != nil { | ||||
| 		return m.Borrowers | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_GetAuthorizedBorrowers_Response_Borrower struct { | ||||
| 	Steamid          *uint64 `protobuf:"fixed64,1,opt,name=steamid" json:"steamid,omitempty"` | ||||
| 	IsPending        *bool   `protobuf:"varint,2,opt,name=is_pending" json:"is_pending,omitempty"` | ||||
| 	IsCanceled       *bool   `protobuf:"varint,3,opt,name=is_canceled" json:"is_canceled,omitempty"` | ||||
| 	TimeCreated      *uint32 `protobuf:"varint,4,opt,name=time_created" json:"time_created,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetAuthorizedBorrowers_Response_Borrower) Reset() { | ||||
| 	*m = CDeviceAuth_GetAuthorizedBorrowers_Response_Borrower{} | ||||
| } | ||||
| func (m *CDeviceAuth_GetAuthorizedBorrowers_Response_Borrower) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_GetAuthorizedBorrowers_Response_Borrower) ProtoMessage() {} | ||||
| func (*CDeviceAuth_GetAuthorizedBorrowers_Response_Borrower) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{11, 0} | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetAuthorizedBorrowers_Response_Borrower) GetSteamid() uint64 { | ||||
| 	if m != nil && m.Steamid != nil { | ||||
| 		return *m.Steamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetAuthorizedBorrowers_Response_Borrower) GetIsPending() bool { | ||||
| 	if m != nil && m.IsPending != nil { | ||||
| 		return *m.IsPending | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetAuthorizedBorrowers_Response_Borrower) GetIsCanceled() bool { | ||||
| 	if m != nil && m.IsCanceled != nil { | ||||
| 		return *m.IsCanceled | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_GetAuthorizedBorrowers_Response_Borrower) GetTimeCreated() uint32 { | ||||
| 	if m != nil && m.TimeCreated != nil { | ||||
| 		return *m.TimeCreated | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_AddAuthorizedBorrowers_Request struct { | ||||
| 	Steamid          *uint64  `protobuf:"fixed64,1,opt,name=steamid" json:"steamid,omitempty"` | ||||
| 	SteamidBorrower  []uint64 `protobuf:"fixed64,2,rep,name=steamid_borrower" json:"steamid_borrower,omitempty"` | ||||
| 	XXX_unrecognized []byte   `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_AddAuthorizedBorrowers_Request) Reset() { | ||||
| 	*m = CDeviceAuth_AddAuthorizedBorrowers_Request{} | ||||
| } | ||||
| func (m *CDeviceAuth_AddAuthorizedBorrowers_Request) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_AddAuthorizedBorrowers_Request) ProtoMessage() {} | ||||
| func (*CDeviceAuth_AddAuthorizedBorrowers_Request) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{12} | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_AddAuthorizedBorrowers_Request) GetSteamid() uint64 { | ||||
| 	if m != nil && m.Steamid != nil { | ||||
| 		return *m.Steamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_AddAuthorizedBorrowers_Request) GetSteamidBorrower() []uint64 { | ||||
| 	if m != nil { | ||||
| 		return m.SteamidBorrower | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_AddAuthorizedBorrowers_Response struct { | ||||
| 	SecondsToWait    *int32 `protobuf:"varint,1,opt,name=seconds_to_wait" json:"seconds_to_wait,omitempty"` | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_AddAuthorizedBorrowers_Response) Reset() { | ||||
| 	*m = CDeviceAuth_AddAuthorizedBorrowers_Response{} | ||||
| } | ||||
| func (m *CDeviceAuth_AddAuthorizedBorrowers_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_AddAuthorizedBorrowers_Response) ProtoMessage() {} | ||||
| func (*CDeviceAuth_AddAuthorizedBorrowers_Response) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{13} | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_AddAuthorizedBorrowers_Response) GetSecondsToWait() int32 { | ||||
| 	if m != nil && m.SecondsToWait != nil { | ||||
| 		return *m.SecondsToWait | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_RemoveAuthorizedBorrowers_Request struct { | ||||
| 	Steamid          *uint64  `protobuf:"fixed64,1,opt,name=steamid" json:"steamid,omitempty"` | ||||
| 	SteamidBorrower  []uint64 `protobuf:"fixed64,2,rep,name=steamid_borrower" json:"steamid_borrower,omitempty"` | ||||
| 	XXX_unrecognized []byte   `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_RemoveAuthorizedBorrowers_Request) Reset() { | ||||
| 	*m = CDeviceAuth_RemoveAuthorizedBorrowers_Request{} | ||||
| } | ||||
| func (m *CDeviceAuth_RemoveAuthorizedBorrowers_Request) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_RemoveAuthorizedBorrowers_Request) ProtoMessage() {} | ||||
| func (*CDeviceAuth_RemoveAuthorizedBorrowers_Request) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{14} | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_RemoveAuthorizedBorrowers_Request) GetSteamid() uint64 { | ||||
| 	if m != nil && m.Steamid != nil { | ||||
| 		return *m.Steamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_RemoveAuthorizedBorrowers_Request) GetSteamidBorrower() []uint64 { | ||||
| 	if m != nil { | ||||
| 		return m.SteamidBorrower | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type CDeviceAuth_RemoveAuthorizedBorrowers_Response struct { | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CDeviceAuth_RemoveAuthorizedBorrowers_Response) Reset() { | ||||
| 	*m = CDeviceAuth_RemoveAuthorizedBorrowers_Response{} | ||||
| } | ||||
| func (m *CDeviceAuth_RemoveAuthorizedBorrowers_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CDeviceAuth_RemoveAuthorizedBorrowers_Response) ProtoMessage() {} | ||||
| func (*CDeviceAuth_RemoveAuthorizedBorrowers_Response) Descriptor() ([]byte, []int) { | ||||
| 	return deviceauth_fileDescriptor0, []int{15} | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	proto.RegisterType((*CDeviceAuth_GetOwnAuthorizedDevices_Request)(nil), "CDeviceAuth_GetOwnAuthorizedDevices_Request") | ||||
| 	proto.RegisterType((*CDeviceAuth_GetOwnAuthorizedDevices_Response)(nil), "CDeviceAuth_GetOwnAuthorizedDevices_Response") | ||||
| 	proto.RegisterType((*CDeviceAuth_GetOwnAuthorizedDevices_Response_Device)(nil), "CDeviceAuth_GetOwnAuthorizedDevices_Response.Device") | ||||
| 	proto.RegisterType((*CDeviceAuth_AcceptAuthorizationRequest_Request)(nil), "CDeviceAuth_AcceptAuthorizationRequest_Request") | ||||
| 	proto.RegisterType((*CDeviceAuth_AcceptAuthorizationRequest_Response)(nil), "CDeviceAuth_AcceptAuthorizationRequest_Response") | ||||
| 	proto.RegisterType((*CDeviceAuth_AuthorizeRemoteDevice_Request)(nil), "CDeviceAuth_AuthorizeRemoteDevice_Request") | ||||
| 	proto.RegisterType((*CDeviceAuth_AuthorizeRemoteDevice_Response)(nil), "CDeviceAuth_AuthorizeRemoteDevice_Response") | ||||
| 	proto.RegisterType((*CDeviceAuth_DeauthorizeRemoteDevice_Request)(nil), "CDeviceAuth_DeauthorizeRemoteDevice_Request") | ||||
| 	proto.RegisterType((*CDeviceAuth_DeauthorizeRemoteDevice_Response)(nil), "CDeviceAuth_DeauthorizeRemoteDevice_Response") | ||||
| 	proto.RegisterType((*CDeviceAuth_GetUsedAuthorizedDevices_Request)(nil), "CDeviceAuth_GetUsedAuthorizedDevices_Request") | ||||
| 	proto.RegisterType((*CDeviceAuth_GetUsedAuthorizedDevices_Response)(nil), "CDeviceAuth_GetUsedAuthorizedDevices_Response") | ||||
| 	proto.RegisterType((*CDeviceAuth_GetUsedAuthorizedDevices_Response_Device)(nil), "CDeviceAuth_GetUsedAuthorizedDevices_Response.Device") | ||||
| 	proto.RegisterType((*CDeviceAuth_GetAuthorizedBorrowers_Request)(nil), "CDeviceAuth_GetAuthorizedBorrowers_Request") | ||||
| 	proto.RegisterType((*CDeviceAuth_GetAuthorizedBorrowers_Response)(nil), "CDeviceAuth_GetAuthorizedBorrowers_Response") | ||||
| 	proto.RegisterType((*CDeviceAuth_GetAuthorizedBorrowers_Response_Borrower)(nil), "CDeviceAuth_GetAuthorizedBorrowers_Response.Borrower") | ||||
| 	proto.RegisterType((*CDeviceAuth_AddAuthorizedBorrowers_Request)(nil), "CDeviceAuth_AddAuthorizedBorrowers_Request") | ||||
| 	proto.RegisterType((*CDeviceAuth_AddAuthorizedBorrowers_Response)(nil), "CDeviceAuth_AddAuthorizedBorrowers_Response") | ||||
| 	proto.RegisterType((*CDeviceAuth_RemoveAuthorizedBorrowers_Request)(nil), "CDeviceAuth_RemoveAuthorizedBorrowers_Request") | ||||
| 	proto.RegisterType((*CDeviceAuth_RemoveAuthorizedBorrowers_Response)(nil), "CDeviceAuth_RemoveAuthorizedBorrowers_Response") | ||||
| } | ||||
|  | ||||
| var deviceauth_fileDescriptor0 = []byte{ | ||||
| 	// 934 bytes of a gzipped FileDescriptorProto | ||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x56, 0xdf, 0x4e, 0x3b, 0x45, | ||||
| 	0x14, 0xce, 0xb6, 0x50, 0x60, 0x10, 0x91, 0x51, 0xa0, 0xec, 0x85, 0x4e, 0x56, 0x2f, 0x10, 0xca, | ||||
| 	0x80, 0x04, 0xe3, 0xff, 0x3f, 0x20, 0xa2, 0x17, 0x26, 0x26, 0x18, 0xa3, 0x72, 0xb3, 0x99, 0xee, | ||||
| 	0x0e, 0x74, 0x62, 0xbb, 0xbb, 0xee, 0x4c, 0x69, 0xf0, 0x8a, 0x98, 0xf8, 0x12, 0xfa, 0x06, 0x5e, | ||||
| 	0x19, 0x13, 0xa2, 0x89, 0x5e, 0xf8, 0x0e, 0xbe, 0x8d, 0x57, 0xbf, 0xb3, 0xb3, 0xb3, 0x85, 0x6d, | ||||
| 	0x77, 0x4b, 0xb7, 0xe1, 0xaa, 0x9b, 0x73, 0xce, 0x9c, 0xf9, 0xce, 0x99, 0xf3, 0x7d, 0xa7, 0x68, | ||||
| 	0x47, 0x2a, 0xce, 0x7a, 0x3d, 0x2e, 0x25, 0xbb, 0xe2, 0xd2, 0xf5, 0xf9, 0xb5, 0xf0, 0x38, 0xeb, | ||||
| 	0xab, 0x0e, 0xd5, 0x0e, 0xaf, 0x2b, 0x78, 0xa0, 0x68, 0x14, 0x87, 0x2a, 0xb4, 0x5b, 0xf9, 0xd8, | ||||
| 	0x7e, 0x20, 0x2e, 0x05, 0xf7, 0xdd, 0x36, 0x93, 0x7c, 0x3c, 0xda, 0xf9, 0x16, 0xed, 0x7e, 0x72, | ||||
| 	0xaa, 0xd3, 0x1d, 0x43, 0x3a, 0xf7, 0x33, 0xae, 0xbe, 0x1c, 0x04, 0xc9, 0x67, 0x18, 0x8b, 0x1f, | ||||
| 	0xb9, 0x9f, 0xba, 0xa4, 0x7b, 0xce, 0x7f, 0xe8, 0x73, 0xa9, 0xf0, 0x2a, 0x5a, 0xd0, 0x39, 0x84, | ||||
| 	0xdf, 0xb4, 0x88, 0xb5, 0xdd, 0xc0, 0x4d, 0xf4, 0x82, 0x08, 0xbc, 0x6e, 0xdf, 0xe7, 0xae, 0xc7, | ||||
| 	0x02, 0x8f, 0x77, 0xb9, 0xdf, 0xac, 0x81, 0x67, 0xd1, 0xf9, 0xab, 0x86, 0x5a, 0xd3, 0xa5, 0x96, | ||||
| 	0x51, 0x18, 0x48, 0x8e, 0x3f, 0x45, 0x0b, 0x69, 0x61, 0x12, 0x72, 0xd7, 0xb7, 0x97, 0x0f, 0x8f, | ||||
| 	0x68, 0x95, 0xf3, 0x34, 0x35, 0xd8, 0xff, 0x5a, 0xa8, 0x91, 0x7e, 0xe2, 0x2d, 0xb4, 0x96, 0x34, | ||||
| 	0xc9, 0xf4, 0xcb, 0x55, 0xe1, 0xf7, 0x3c, 0x30, 0xb8, 0x5f, 0x44, 0xcb, 0xc6, 0x1a, 0xb0, 0x1e, | ||||
| 	0xd7, 0x90, 0x97, 0x30, 0x46, 0x48, 0x48, 0x37, 0xe2, 0x81, 0x2f, 0x82, 0xab, 0x66, 0x3d, 0x29, | ||||
| 	0x23, 0x09, 0x04, 0xdb, 0xb0, 0xb6, 0x39, 0x6d, 0xdc, 0x40, 0xcf, 0x77, 0x99, 0x54, 0xae, 0x12, | ||||
| 	0x3d, 0xee, 0xf6, 0x25, 0xd8, 0xe7, 0xc1, 0xbe, 0x92, 0x74, 0x43, 0xdb, 0xdb, 0x61, 0x1c, 0x87, | ||||
| 	0x03, 0x1e, 0xbb, 0xd0, 0xa7, 0x86, 0xbe, 0x6f, 0x13, 0xad, 0x6a, 0x0f, 0x8b, 0x22, 0x37, 0xea, | ||||
| 	0xb2, 0x1b, 0x38, 0xb2, 0xa0, 0x8f, 0xa4, 0x77, 0x76, 0x45, 0x4f, 0x28, 0xb0, 0x2d, 0xea, 0xd6, | ||||
| 	0xfd, 0x6c, 0xa1, 0x5c, 0xe9, 0xc7, 0x9e, 0xc7, 0x23, 0x95, 0x95, 0xce, 0x94, 0x08, 0x03, 0xf3, | ||||
| 	0x20, 0xe5, 0x0f, 0x53, 0x58, 0x7b, 0x4d, 0xbb, 0xd6, 0xd0, 0x92, 0x76, 0x79, 0xa1, 0xcf, 0x75, | ||||
| 	0x95, 0x0d, 0xfc, 0x12, 0x7a, 0xee, 0x32, 0x0e, 0x7b, 0x6e, 0x96, 0x23, 0x29, 0xb3, 0xe1, 0xbc, | ||||
| 	0x81, 0xf6, 0xa7, 0x86, 0x91, 0x3e, 0x82, 0xf3, 0x0d, 0x7a, 0x3d, 0x77, 0x24, 0x7b, 0xae, 0x73, | ||||
| 	0xde, 0x0b, 0x15, 0x4f, 0x3d, 0xb3, 0x80, 0x76, 0x5a, 0x68, 0x67, 0x9a, 0xc4, 0x06, 0xc6, 0x77, | ||||
| 	0xf9, 0xb1, 0x3e, 0xd5, 0x64, 0x79, 0x1a, 0x20, 0x34, 0x3f, 0xd6, 0xe5, 0xa9, 0x0d, 0x94, 0x8f, | ||||
| 	0xc6, 0x68, 0xf0, 0x35, 0x0c, 0xcc, 0xf4, 0x14, 0x73, 0xfe, 0xb7, 0xd0, 0xde, 0x94, 0x19, 0x0c, | ||||
| 	0x93, 0xce, 0x46, 0x99, 0xf4, 0x26, 0xad, 0x94, 0x20, 0xa3, 0xd2, 0xed, 0xec, 0x54, 0x5a, 0x47, | ||||
| 	0x2b, 0xe1, 0x20, 0x00, 0x06, 0x64, 0xb5, 0xa4, 0x73, 0x36, 0x4e, 0x9c, 0x39, 0xcd, 0x82, 0x02, | ||||
| 	0x7a, 0x68, 0x46, 0x39, 0x51, 0xfe, 0xd9, 0x01, 0xfa, 0x3d, 0xec, 0x13, 0xc3, 0xb2, 0x59, 0xe4, | ||||
| 	0x29, 0xb9, 0x31, 0xf3, 0xe4, 0x08, 0xef, 0xfc, 0x67, 0x8d, 0x49, 0x62, 0xf1, 0x95, 0xa6, 0xd9, | ||||
| 	0x9f, 0xa3, 0xa5, 0x8c, 0xee, 0xa5, 0xed, 0x9e, 0x94, 0x80, 0x66, 0x26, 0xfb, 0x02, 0x2d, 0x66, | ||||
| 	0xdf, 0xe3, 0x95, 0xe4, 0xb5, 0xa9, 0x56, 0xa4, 0x4d, 0xa9, 0x60, 0x01, 0x95, 0x75, 0x77, 0xbd, | ||||
| 	0x98, 0x33, 0x95, 0x35, 0x18, 0x78, 0x99, 0xa7, 0x8f, 0xef, 0x57, 0xed, 0xa3, 0x31, 0x0c, 0xb5, | ||||
| 	0x0d, 0x30, 0xd4, 0x61, 0x3a, 0xcf, 0xf2, 0xdd, 0x2a, 0x4d, 0x6c, 0xba, 0x05, 0x6d, 0x97, 0xdc, | ||||
| 	0x0b, 0x03, 0x5f, 0xc2, 0x0c, 0xb9, 0x03, 0x26, 0x94, 0xbe, 0x61, 0xde, 0xb9, 0xc8, 0x0f, 0x79, | ||||
| 	0xc2, 0xa5, 0x6b, 0xfe, 0x44, 0x18, 0x0f, 0xf2, 0x72, 0x3a, 0x29, 0x77, 0x0a, 0xf3, 0xf0, 0xcf, | ||||
| 	0x65, 0x84, 0xee, 0x4f, 0xe0, 0x5f, 0x2c, 0xb4, 0x59, 0xb2, 0x7f, 0x70, 0x8b, 0x56, 0x58, 0xa0, | ||||
| 	0xf6, 0x5e, 0xa5, 0x9d, 0xe6, 0x38, 0x3f, 0xdd, 0x35, 0x5f, 0x86, 0x28, 0xd2, 0x15, 0x52, 0x91, | ||||
| 	0xf0, 0x92, 0x0c, 0xc5, 0xc6, 0x27, 0x86, 0xe2, 0xf8, 0xce, 0x42, 0x76, 0xb9, 0x34, 0xe3, 0xfd, | ||||
| 	0x8a, 0xab, 0xc4, 0x3e, 0xa0, 0x55, 0x45, 0xff, 0x08, 0x50, 0x1e, 0xa4, 0x81, 0x84, 0x05, 0x43, | ||||
| 	0x8c, 0x3a, 0x98, 0xc4, 0x69, 0x34, 0x69, 0xdf, 0x80, 0x2f, 0x54, 0x1d, 0x1e, 0x13, 0x20, 0x7e, | ||||
| 	0x2c, 0xf1, 0x6f, 0x16, 0x5a, 0x2f, 0x94, 0x71, 0xbc, 0x43, 0xa7, 0xde, 0x21, 0xf6, 0x2e, 0xad, | ||||
| 	0xb0, 0x16, 0xde, 0x06, 0xa0, 0x47, 0xc3, 0x18, 0x02, 0x0a, 0x05, 0xf0, 0x92, 0x40, 0xd3, 0x4c, | ||||
| 	0xa2, 0x3a, 0x4c, 0x91, 0x0e, 0x93, 0xc4, 0x10, 0x2d, 0x43, 0x8f, 0x7f, 0x85, 0x09, 0x28, 0x91, | ||||
| 	0xfa, 0x91, 0x09, 0x78, 0x64, 0xd7, 0x8c, 0x4c, 0xc0, 0xa3, 0xeb, 0xe3, 0x55, 0x80, 0xfc, 0xca, | ||||
| 	0x39, 0xbf, 0x06, 0xc1, 0xd5, 0x78, 0x0d, 0xd0, 0x5c, 0x8f, 0xf1, 0xdf, 0x16, 0x6a, 0x96, 0xa9, | ||||
| 	0x3a, 0xde, 0xa3, 0x55, 0xf6, 0x8f, 0x4d, 0xab, 0xed, 0x0a, 0xe7, 0x63, 0x00, 0xf8, 0xfe, 0xe4, | ||||
| 	0x11, 0xd5, 0x0f, 0x4e, 0x52, 0x5d, 0x27, 0x86, 0x9b, 0x3e, 0xb9, 0x82, 0x6d, 0x21, 0x09, 0xa0, | ||||
| 	0xff, 0xc3, 0x42, 0x1b, 0xc5, 0x22, 0x89, 0x77, 0xe9, 0xf4, 0xea, 0x6f, 0xb7, 0xaa, 0xc8, 0xae, | ||||
| 	0xf3, 0x01, 0xe0, 0x7e, 0xe7, 0x21, 0x6e, 0x3d, 0x95, 0xe9, 0x04, 0x80, 0xa4, 0x1a, 0x9c, 0x80, | ||||
| 	0xef, 0xe1, 0x48, 0x0f, 0x6b, 0xc2, 0xbf, 0x03, 0xe8, 0x62, 0xb1, 0x1b, 0x01, 0x3d, 0x59, 0x6a, | ||||
| 	0x47, 0x40, 0x3f, 0x22, 0x9f, 0xce, 0x7b, 0x00, 0xfa, 0x2d, 0x08, 0x2a, 0x07, 0x6b, 0xfe, 0x49, | ||||
| 	0x16, 0x09, 0xc5, 0x3f, 0x16, 0xda, 0x2a, 0xd5, 0x3e, 0x4c, 0x69, 0x25, 0xfd, 0xb5, 0xf7, 0x2b, | ||||
| 	0x6a, 0xaa, 0xf3, 0x21, 0x60, 0x7f, 0x37, 0x8d, 0x9b, 0x05, 0xbe, 0xfd, 0x1a, 0x9c, 0x27, 0x5f, | ||||
| 	0x88, 0x76, 0xcc, 0xe2, 0x1b, 0xf2, 0x55, 0x87, 0xc5, 0x09, 0x3f, 0x25, 0x57, 0x0a, 0x7e, 0x25, | ||||
| 	0x7c, 0xc4, 0x49, 0xd8, 0x49, 0xfd, 0xd6, 0xb2, 0x9e, 0x05, 0x00, 0x00, 0xff, 0xff, 0x27, 0xc5, | ||||
| 	0x15, 0xba, 0x30, 0x0d, 0x00, 0x00, | ||||
| } | ||||
							
								
								
									
										850
									
								
								vendor/github.com/Philipp15b/go-steam/protocol/protobuf/unified/gamenotifications.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										850
									
								
								vendor/github.com/Philipp15b/go-steam/protocol/protobuf/unified/gamenotifications.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,850 +0,0 @@ | ||||
| // Code generated by protoc-gen-go. | ||||
| // source: steammessages_gamenotifications.steamclient.proto | ||||
| // DO NOT EDIT! | ||||
|  | ||||
| package unified | ||||
|  | ||||
| import proto "github.com/golang/protobuf/proto" | ||||
| import fmt "fmt" | ||||
| import math "math" | ||||
|  | ||||
| // Reference imports to suppress errors if they are not otherwise used. | ||||
| var _ = proto.Marshal | ||||
| var _ = fmt.Errorf | ||||
| var _ = math.Inf | ||||
|  | ||||
| type CGameNotifications_Variable struct { | ||||
| 	Key              *string `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` | ||||
| 	Value            *string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_Variable) Reset()                    { *m = CGameNotifications_Variable{} } | ||||
| func (m *CGameNotifications_Variable) String() string            { return proto.CompactTextString(m) } | ||||
| func (*CGameNotifications_Variable) ProtoMessage()               {} | ||||
| func (*CGameNotifications_Variable) Descriptor() ([]byte, []int) { return gamenotifications_fileDescriptor0, []int{0} } | ||||
|  | ||||
| func (m *CGameNotifications_Variable) GetKey() string { | ||||
| 	if m != nil && m.Key != nil { | ||||
| 		return *m.Key | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_Variable) GetValue() string { | ||||
| 	if m != nil && m.Value != nil { | ||||
| 		return *m.Value | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| type CGameNotifications_LocalizedText struct { | ||||
| 	Token            *string                        `protobuf:"bytes,1,opt,name=token" json:"token,omitempty"` | ||||
| 	Variables        []*CGameNotifications_Variable `protobuf:"bytes,2,rep,name=variables" json:"variables,omitempty"` | ||||
| 	RenderedText     *string                        `protobuf:"bytes,3,opt,name=rendered_text" json:"rendered_text,omitempty"` | ||||
| 	XXX_unrecognized []byte                         `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_LocalizedText) Reset()         { *m = CGameNotifications_LocalizedText{} } | ||||
| func (m *CGameNotifications_LocalizedText) String() string { return proto.CompactTextString(m) } | ||||
| func (*CGameNotifications_LocalizedText) ProtoMessage()    {} | ||||
| func (*CGameNotifications_LocalizedText) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{1} | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_LocalizedText) GetToken() string { | ||||
| 	if m != nil && m.Token != nil { | ||||
| 		return *m.Token | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_LocalizedText) GetVariables() []*CGameNotifications_Variable { | ||||
| 	if m != nil { | ||||
| 		return m.Variables | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_LocalizedText) GetRenderedText() string { | ||||
| 	if m != nil && m.RenderedText != nil { | ||||
| 		return *m.RenderedText | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| type CGameNotifications_UserStatus struct { | ||||
| 	Steamid          *uint64                           `protobuf:"fixed64,1,opt,name=steamid" json:"steamid,omitempty"` | ||||
| 	State            *string                           `protobuf:"bytes,2,opt,name=state" json:"state,omitempty"` | ||||
| 	Title            *CGameNotifications_LocalizedText `protobuf:"bytes,3,opt,name=title" json:"title,omitempty"` | ||||
| 	Message          *CGameNotifications_LocalizedText `protobuf:"bytes,4,opt,name=message" json:"message,omitempty"` | ||||
| 	XXX_unrecognized []byte                            `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_UserStatus) Reset()                    { *m = CGameNotifications_UserStatus{} } | ||||
| func (m *CGameNotifications_UserStatus) String() string            { return proto.CompactTextString(m) } | ||||
| func (*CGameNotifications_UserStatus) ProtoMessage()               {} | ||||
| func (*CGameNotifications_UserStatus) Descriptor() ([]byte, []int) { return gamenotifications_fileDescriptor0, []int{2} } | ||||
|  | ||||
| func (m *CGameNotifications_UserStatus) GetSteamid() uint64 { | ||||
| 	if m != nil && m.Steamid != nil { | ||||
| 		return *m.Steamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_UserStatus) GetState() string { | ||||
| 	if m != nil && m.State != nil { | ||||
| 		return *m.State | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_UserStatus) GetTitle() *CGameNotifications_LocalizedText { | ||||
| 	if m != nil { | ||||
| 		return m.Title | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_UserStatus) GetMessage() *CGameNotifications_LocalizedText { | ||||
| 	if m != nil { | ||||
| 		return m.Message | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type CGameNotifications_CreateSession_Request struct { | ||||
| 	Appid            *uint32                           `protobuf:"varint,1,opt,name=appid" json:"appid,omitempty"` | ||||
| 	Context          *uint64                           `protobuf:"varint,2,opt,name=context" json:"context,omitempty"` | ||||
| 	Title            *CGameNotifications_LocalizedText `protobuf:"bytes,3,opt,name=title" json:"title,omitempty"` | ||||
| 	Users            []*CGameNotifications_UserStatus  `protobuf:"bytes,4,rep,name=users" json:"users,omitempty"` | ||||
| 	Steamid          *uint64                           `protobuf:"fixed64,5,opt,name=steamid" json:"steamid,omitempty"` | ||||
| 	XXX_unrecognized []byte                            `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_CreateSession_Request) Reset() { | ||||
| 	*m = CGameNotifications_CreateSession_Request{} | ||||
| } | ||||
| func (m *CGameNotifications_CreateSession_Request) String() string { return proto.CompactTextString(m) } | ||||
| func (*CGameNotifications_CreateSession_Request) ProtoMessage()    {} | ||||
| func (*CGameNotifications_CreateSession_Request) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{3} | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_CreateSession_Request) GetAppid() uint32 { | ||||
| 	if m != nil && m.Appid != nil { | ||||
| 		return *m.Appid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_CreateSession_Request) GetContext() uint64 { | ||||
| 	if m != nil && m.Context != nil { | ||||
| 		return *m.Context | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_CreateSession_Request) GetTitle() *CGameNotifications_LocalizedText { | ||||
| 	if m != nil { | ||||
| 		return m.Title | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_CreateSession_Request) GetUsers() []*CGameNotifications_UserStatus { | ||||
| 	if m != nil { | ||||
| 		return m.Users | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_CreateSession_Request) GetSteamid() uint64 { | ||||
| 	if m != nil && m.Steamid != nil { | ||||
| 		return *m.Steamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CGameNotifications_CreateSession_Response struct { | ||||
| 	Sessionid        *uint64 `protobuf:"varint,1,opt,name=sessionid" json:"sessionid,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_CreateSession_Response) Reset() { | ||||
| 	*m = CGameNotifications_CreateSession_Response{} | ||||
| } | ||||
| func (m *CGameNotifications_CreateSession_Response) String() string { return proto.CompactTextString(m) } | ||||
| func (*CGameNotifications_CreateSession_Response) ProtoMessage()    {} | ||||
| func (*CGameNotifications_CreateSession_Response) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{4} | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_CreateSession_Response) GetSessionid() uint64 { | ||||
| 	if m != nil && m.Sessionid != nil { | ||||
| 		return *m.Sessionid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CGameNotifications_DeleteSession_Request struct { | ||||
| 	Sessionid        *uint64 `protobuf:"varint,1,opt,name=sessionid" json:"sessionid,omitempty"` | ||||
| 	Appid            *uint32 `protobuf:"varint,2,opt,name=appid" json:"appid,omitempty"` | ||||
| 	Steamid          *uint64 `protobuf:"fixed64,3,opt,name=steamid" json:"steamid,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_DeleteSession_Request) Reset() { | ||||
| 	*m = CGameNotifications_DeleteSession_Request{} | ||||
| } | ||||
| func (m *CGameNotifications_DeleteSession_Request) String() string { return proto.CompactTextString(m) } | ||||
| func (*CGameNotifications_DeleteSession_Request) ProtoMessage()    {} | ||||
| func (*CGameNotifications_DeleteSession_Request) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{5} | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_DeleteSession_Request) GetSessionid() uint64 { | ||||
| 	if m != nil && m.Sessionid != nil { | ||||
| 		return *m.Sessionid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_DeleteSession_Request) GetAppid() uint32 { | ||||
| 	if m != nil && m.Appid != nil { | ||||
| 		return *m.Appid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_DeleteSession_Request) GetSteamid() uint64 { | ||||
| 	if m != nil && m.Steamid != nil { | ||||
| 		return *m.Steamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CGameNotifications_DeleteSession_Response struct { | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_DeleteSession_Response) Reset() { | ||||
| 	*m = CGameNotifications_DeleteSession_Response{} | ||||
| } | ||||
| func (m *CGameNotifications_DeleteSession_Response) String() string { return proto.CompactTextString(m) } | ||||
| func (*CGameNotifications_DeleteSession_Response) ProtoMessage()    {} | ||||
| func (*CGameNotifications_DeleteSession_Response) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{6} | ||||
| } | ||||
|  | ||||
| type CGameNotifications_UpdateSession_Request struct { | ||||
| 	Sessionid        *uint64                           `protobuf:"varint,1,opt,name=sessionid" json:"sessionid,omitempty"` | ||||
| 	Appid            *uint32                           `protobuf:"varint,2,opt,name=appid" json:"appid,omitempty"` | ||||
| 	Title            *CGameNotifications_LocalizedText `protobuf:"bytes,3,opt,name=title" json:"title,omitempty"` | ||||
| 	Users            []*CGameNotifications_UserStatus  `protobuf:"bytes,4,rep,name=users" json:"users,omitempty"` | ||||
| 	Steamid          *uint64                           `protobuf:"fixed64,6,opt,name=steamid" json:"steamid,omitempty"` | ||||
| 	XXX_unrecognized []byte                            `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_UpdateSession_Request) Reset() { | ||||
| 	*m = CGameNotifications_UpdateSession_Request{} | ||||
| } | ||||
| func (m *CGameNotifications_UpdateSession_Request) String() string { return proto.CompactTextString(m) } | ||||
| func (*CGameNotifications_UpdateSession_Request) ProtoMessage()    {} | ||||
| func (*CGameNotifications_UpdateSession_Request) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{7} | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_UpdateSession_Request) GetSessionid() uint64 { | ||||
| 	if m != nil && m.Sessionid != nil { | ||||
| 		return *m.Sessionid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_UpdateSession_Request) GetAppid() uint32 { | ||||
| 	if m != nil && m.Appid != nil { | ||||
| 		return *m.Appid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_UpdateSession_Request) GetTitle() *CGameNotifications_LocalizedText { | ||||
| 	if m != nil { | ||||
| 		return m.Title | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_UpdateSession_Request) GetUsers() []*CGameNotifications_UserStatus { | ||||
| 	if m != nil { | ||||
| 		return m.Users | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_UpdateSession_Request) GetSteamid() uint64 { | ||||
| 	if m != nil && m.Steamid != nil { | ||||
| 		return *m.Steamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CGameNotifications_UpdateSession_Response struct { | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_UpdateSession_Response) Reset() { | ||||
| 	*m = CGameNotifications_UpdateSession_Response{} | ||||
| } | ||||
| func (m *CGameNotifications_UpdateSession_Response) String() string { return proto.CompactTextString(m) } | ||||
| func (*CGameNotifications_UpdateSession_Response) ProtoMessage()    {} | ||||
| func (*CGameNotifications_UpdateSession_Response) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{8} | ||||
| } | ||||
|  | ||||
| type CGameNotifications_EnumerateSessions_Request struct { | ||||
| 	Appid                  *uint32 `protobuf:"varint,1,opt,name=appid" json:"appid,omitempty"` | ||||
| 	IncludeAllUserMessages *bool   `protobuf:"varint,3,opt,name=include_all_user_messages" json:"include_all_user_messages,omitempty"` | ||||
| 	IncludeAuthUserMessage *bool   `protobuf:"varint,4,opt,name=include_auth_user_message" json:"include_auth_user_message,omitempty"` | ||||
| 	Language               *string `protobuf:"bytes,5,opt,name=language" json:"language,omitempty"` | ||||
| 	XXX_unrecognized       []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_EnumerateSessions_Request) Reset() { | ||||
| 	*m = CGameNotifications_EnumerateSessions_Request{} | ||||
| } | ||||
| func (m *CGameNotifications_EnumerateSessions_Request) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CGameNotifications_EnumerateSessions_Request) ProtoMessage() {} | ||||
| func (*CGameNotifications_EnumerateSessions_Request) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{9} | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_EnumerateSessions_Request) GetAppid() uint32 { | ||||
| 	if m != nil && m.Appid != nil { | ||||
| 		return *m.Appid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_EnumerateSessions_Request) GetIncludeAllUserMessages() bool { | ||||
| 	if m != nil && m.IncludeAllUserMessages != nil { | ||||
| 		return *m.IncludeAllUserMessages | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_EnumerateSessions_Request) GetIncludeAuthUserMessage() bool { | ||||
| 	if m != nil && m.IncludeAuthUserMessage != nil { | ||||
| 		return *m.IncludeAuthUserMessage | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_EnumerateSessions_Request) GetLanguage() string { | ||||
| 	if m != nil && m.Language != nil { | ||||
| 		return *m.Language | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| type CGameNotifications_Session struct { | ||||
| 	Sessionid        *uint64                           `protobuf:"varint,1,opt,name=sessionid" json:"sessionid,omitempty"` | ||||
| 	Appid            *uint64                           `protobuf:"varint,2,opt,name=appid" json:"appid,omitempty"` | ||||
| 	Context          *uint64                           `protobuf:"varint,3,opt,name=context" json:"context,omitempty"` | ||||
| 	Title            *CGameNotifications_LocalizedText `protobuf:"bytes,4,opt,name=title" json:"title,omitempty"` | ||||
| 	TimeCreated      *uint32                           `protobuf:"varint,5,opt,name=time_created" json:"time_created,omitempty"` | ||||
| 	TimeUpdated      *uint32                           `protobuf:"varint,6,opt,name=time_updated" json:"time_updated,omitempty"` | ||||
| 	UserStatus       []*CGameNotifications_UserStatus  `protobuf:"bytes,7,rep,name=user_status" json:"user_status,omitempty"` | ||||
| 	XXX_unrecognized []byte                            `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_Session) Reset()                    { *m = CGameNotifications_Session{} } | ||||
| func (m *CGameNotifications_Session) String() string            { return proto.CompactTextString(m) } | ||||
| func (*CGameNotifications_Session) ProtoMessage()               {} | ||||
| func (*CGameNotifications_Session) Descriptor() ([]byte, []int) { return gamenotifications_fileDescriptor0, []int{10} } | ||||
|  | ||||
| func (m *CGameNotifications_Session) GetSessionid() uint64 { | ||||
| 	if m != nil && m.Sessionid != nil { | ||||
| 		return *m.Sessionid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_Session) GetAppid() uint64 { | ||||
| 	if m != nil && m.Appid != nil { | ||||
| 		return *m.Appid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_Session) GetContext() uint64 { | ||||
| 	if m != nil && m.Context != nil { | ||||
| 		return *m.Context | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_Session) GetTitle() *CGameNotifications_LocalizedText { | ||||
| 	if m != nil { | ||||
| 		return m.Title | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_Session) GetTimeCreated() uint32 { | ||||
| 	if m != nil && m.TimeCreated != nil { | ||||
| 		return *m.TimeCreated | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_Session) GetTimeUpdated() uint32 { | ||||
| 	if m != nil && m.TimeUpdated != nil { | ||||
| 		return *m.TimeUpdated | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_Session) GetUserStatus() []*CGameNotifications_UserStatus { | ||||
| 	if m != nil { | ||||
| 		return m.UserStatus | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type CGameNotifications_EnumerateSessions_Response struct { | ||||
| 	Sessions         []*CGameNotifications_Session `protobuf:"bytes,1,rep,name=sessions" json:"sessions,omitempty"` | ||||
| 	XXX_unrecognized []byte                        `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_EnumerateSessions_Response) Reset() { | ||||
| 	*m = CGameNotifications_EnumerateSessions_Response{} | ||||
| } | ||||
| func (m *CGameNotifications_EnumerateSessions_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CGameNotifications_EnumerateSessions_Response) ProtoMessage() {} | ||||
| func (*CGameNotifications_EnumerateSessions_Response) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{11} | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_EnumerateSessions_Response) GetSessions() []*CGameNotifications_Session { | ||||
| 	if m != nil { | ||||
| 		return m.Sessions | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type CGameNotifications_GetSessionDetails_Request struct { | ||||
| 	Sessions         []*CGameNotifications_GetSessionDetails_Request_RequestedSession `protobuf:"bytes,1,rep,name=sessions" json:"sessions,omitempty"` | ||||
| 	Appid            *uint32                                                          `protobuf:"varint,2,opt,name=appid" json:"appid,omitempty"` | ||||
| 	Language         *string                                                          `protobuf:"bytes,3,opt,name=language" json:"language,omitempty"` | ||||
| 	XXX_unrecognized []byte                                                           `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_GetSessionDetails_Request) Reset() { | ||||
| 	*m = CGameNotifications_GetSessionDetails_Request{} | ||||
| } | ||||
| func (m *CGameNotifications_GetSessionDetails_Request) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CGameNotifications_GetSessionDetails_Request) ProtoMessage() {} | ||||
| func (*CGameNotifications_GetSessionDetails_Request) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{12} | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_GetSessionDetails_Request) GetSessions() []*CGameNotifications_GetSessionDetails_Request_RequestedSession { | ||||
| 	if m != nil { | ||||
| 		return m.Sessions | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_GetSessionDetails_Request) GetAppid() uint32 { | ||||
| 	if m != nil && m.Appid != nil { | ||||
| 		return *m.Appid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_GetSessionDetails_Request) GetLanguage() string { | ||||
| 	if m != nil && m.Language != nil { | ||||
| 		return *m.Language | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| type CGameNotifications_GetSessionDetails_Request_RequestedSession struct { | ||||
| 	Sessionid              *uint64 `protobuf:"varint,1,opt,name=sessionid" json:"sessionid,omitempty"` | ||||
| 	IncludeAuthUserMessage *bool   `protobuf:"varint,3,opt,name=include_auth_user_message" json:"include_auth_user_message,omitempty"` | ||||
| 	XXX_unrecognized       []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_GetSessionDetails_Request_RequestedSession) Reset() { | ||||
| 	*m = CGameNotifications_GetSessionDetails_Request_RequestedSession{} | ||||
| } | ||||
| func (m *CGameNotifications_GetSessionDetails_Request_RequestedSession) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CGameNotifications_GetSessionDetails_Request_RequestedSession) ProtoMessage() {} | ||||
| func (*CGameNotifications_GetSessionDetails_Request_RequestedSession) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{12, 0} | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_GetSessionDetails_Request_RequestedSession) GetSessionid() uint64 { | ||||
| 	if m != nil && m.Sessionid != nil { | ||||
| 		return *m.Sessionid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_GetSessionDetails_Request_RequestedSession) GetIncludeAuthUserMessage() bool { | ||||
| 	if m != nil && m.IncludeAuthUserMessage != nil { | ||||
| 		return *m.IncludeAuthUserMessage | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| type CGameNotifications_GetSessionDetails_Response struct { | ||||
| 	Sessions         []*CGameNotifications_Session `protobuf:"bytes,1,rep,name=sessions" json:"sessions,omitempty"` | ||||
| 	XXX_unrecognized []byte                        `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_GetSessionDetails_Response) Reset() { | ||||
| 	*m = CGameNotifications_GetSessionDetails_Response{} | ||||
| } | ||||
| func (m *CGameNotifications_GetSessionDetails_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CGameNotifications_GetSessionDetails_Response) ProtoMessage() {} | ||||
| func (*CGameNotifications_GetSessionDetails_Response) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{13} | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_GetSessionDetails_Response) GetSessions() []*CGameNotifications_Session { | ||||
| 	if m != nil { | ||||
| 		return m.Sessions | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type GameNotificationSettings struct { | ||||
| 	Appid              *uint32 `protobuf:"varint,1,opt,name=appid" json:"appid,omitempty"` | ||||
| 	AllowNotifications *bool   `protobuf:"varint,2,opt,name=allow_notifications" json:"allow_notifications,omitempty"` | ||||
| 	XXX_unrecognized   []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *GameNotificationSettings) Reset()                    { *m = GameNotificationSettings{} } | ||||
| func (m *GameNotificationSettings) String() string            { return proto.CompactTextString(m) } | ||||
| func (*GameNotificationSettings) ProtoMessage()               {} | ||||
| func (*GameNotificationSettings) Descriptor() ([]byte, []int) { return gamenotifications_fileDescriptor0, []int{14} } | ||||
|  | ||||
| func (m *GameNotificationSettings) GetAppid() uint32 { | ||||
| 	if m != nil && m.Appid != nil { | ||||
| 		return *m.Appid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *GameNotificationSettings) GetAllowNotifications() bool { | ||||
| 	if m != nil && m.AllowNotifications != nil { | ||||
| 		return *m.AllowNotifications | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| type CGameNotifications_UpdateNotificationSettings_Request struct { | ||||
| 	GameNotificationSettings []*GameNotificationSettings `protobuf:"bytes,1,rep,name=game_notification_settings" json:"game_notification_settings,omitempty"` | ||||
| 	XXX_unrecognized         []byte                      `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_UpdateNotificationSettings_Request) Reset() { | ||||
| 	*m = CGameNotifications_UpdateNotificationSettings_Request{} | ||||
| } | ||||
| func (m *CGameNotifications_UpdateNotificationSettings_Request) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CGameNotifications_UpdateNotificationSettings_Request) ProtoMessage() {} | ||||
| func (*CGameNotifications_UpdateNotificationSettings_Request) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{15} | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_UpdateNotificationSettings_Request) GetGameNotificationSettings() []*GameNotificationSettings { | ||||
| 	if m != nil { | ||||
| 		return m.GameNotificationSettings | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type CGameNotifications_UpdateNotificationSettings_Response struct { | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_UpdateNotificationSettings_Response) Reset() { | ||||
| 	*m = CGameNotifications_UpdateNotificationSettings_Response{} | ||||
| } | ||||
| func (m *CGameNotifications_UpdateNotificationSettings_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CGameNotifications_UpdateNotificationSettings_Response) ProtoMessage() {} | ||||
| func (*CGameNotifications_UpdateNotificationSettings_Response) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{16} | ||||
| } | ||||
|  | ||||
| type CGameNotifications_OnNotificationsRequested_Notification struct { | ||||
| 	Steamid          *uint64 `protobuf:"fixed64,1,opt,name=steamid" json:"steamid,omitempty"` | ||||
| 	Appid            *uint32 `protobuf:"varint,2,opt,name=appid" json:"appid,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_OnNotificationsRequested_Notification) Reset() { | ||||
| 	*m = CGameNotifications_OnNotificationsRequested_Notification{} | ||||
| } | ||||
| func (m *CGameNotifications_OnNotificationsRequested_Notification) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CGameNotifications_OnNotificationsRequested_Notification) ProtoMessage() {} | ||||
| func (*CGameNotifications_OnNotificationsRequested_Notification) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{17} | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_OnNotificationsRequested_Notification) GetSteamid() uint64 { | ||||
| 	if m != nil && m.Steamid != nil { | ||||
| 		return *m.Steamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_OnNotificationsRequested_Notification) GetAppid() uint32 { | ||||
| 	if m != nil && m.Appid != nil { | ||||
| 		return *m.Appid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type CGameNotifications_OnUserStatusChanged_Notification struct { | ||||
| 	Steamid          *uint64                        `protobuf:"fixed64,1,opt,name=steamid" json:"steamid,omitempty"` | ||||
| 	Sessionid        *uint64                        `protobuf:"varint,2,opt,name=sessionid" json:"sessionid,omitempty"` | ||||
| 	Appid            *uint32                        `protobuf:"varint,3,opt,name=appid" json:"appid,omitempty"` | ||||
| 	Status           *CGameNotifications_UserStatus `protobuf:"bytes,4,opt,name=status" json:"status,omitempty"` | ||||
| 	Removed          *bool                          `protobuf:"varint,5,opt,name=removed" json:"removed,omitempty"` | ||||
| 	XXX_unrecognized []byte                         `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_OnUserStatusChanged_Notification) Reset() { | ||||
| 	*m = CGameNotifications_OnUserStatusChanged_Notification{} | ||||
| } | ||||
| func (m *CGameNotifications_OnUserStatusChanged_Notification) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*CGameNotifications_OnUserStatusChanged_Notification) ProtoMessage() {} | ||||
| func (*CGameNotifications_OnUserStatusChanged_Notification) Descriptor() ([]byte, []int) { | ||||
| 	return gamenotifications_fileDescriptor0, []int{18} | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_OnUserStatusChanged_Notification) GetSteamid() uint64 { | ||||
| 	if m != nil && m.Steamid != nil { | ||||
| 		return *m.Steamid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_OnUserStatusChanged_Notification) GetSessionid() uint64 { | ||||
| 	if m != nil && m.Sessionid != nil { | ||||
| 		return *m.Sessionid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_OnUserStatusChanged_Notification) GetAppid() uint32 { | ||||
| 	if m != nil && m.Appid != nil { | ||||
| 		return *m.Appid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_OnUserStatusChanged_Notification) GetStatus() *CGameNotifications_UserStatus { | ||||
| 	if m != nil { | ||||
| 		return m.Status | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *CGameNotifications_OnUserStatusChanged_Notification) GetRemoved() bool { | ||||
| 	if m != nil && m.Removed != nil { | ||||
| 		return *m.Removed | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	proto.RegisterType((*CGameNotifications_Variable)(nil), "CGameNotifications_Variable") | ||||
| 	proto.RegisterType((*CGameNotifications_LocalizedText)(nil), "CGameNotifications_LocalizedText") | ||||
| 	proto.RegisterType((*CGameNotifications_UserStatus)(nil), "CGameNotifications_UserStatus") | ||||
| 	proto.RegisterType((*CGameNotifications_CreateSession_Request)(nil), "CGameNotifications_CreateSession_Request") | ||||
| 	proto.RegisterType((*CGameNotifications_CreateSession_Response)(nil), "CGameNotifications_CreateSession_Response") | ||||
| 	proto.RegisterType((*CGameNotifications_DeleteSession_Request)(nil), "CGameNotifications_DeleteSession_Request") | ||||
| 	proto.RegisterType((*CGameNotifications_DeleteSession_Response)(nil), "CGameNotifications_DeleteSession_Response") | ||||
| 	proto.RegisterType((*CGameNotifications_UpdateSession_Request)(nil), "CGameNotifications_UpdateSession_Request") | ||||
| 	proto.RegisterType((*CGameNotifications_UpdateSession_Response)(nil), "CGameNotifications_UpdateSession_Response") | ||||
| 	proto.RegisterType((*CGameNotifications_EnumerateSessions_Request)(nil), "CGameNotifications_EnumerateSessions_Request") | ||||
| 	proto.RegisterType((*CGameNotifications_Session)(nil), "CGameNotifications_Session") | ||||
| 	proto.RegisterType((*CGameNotifications_EnumerateSessions_Response)(nil), "CGameNotifications_EnumerateSessions_Response") | ||||
| 	proto.RegisterType((*CGameNotifications_GetSessionDetails_Request)(nil), "CGameNotifications_GetSessionDetails_Request") | ||||
| 	proto.RegisterType((*CGameNotifications_GetSessionDetails_Request_RequestedSession)(nil), "CGameNotifications_GetSessionDetails_Request.RequestedSession") | ||||
| 	proto.RegisterType((*CGameNotifications_GetSessionDetails_Response)(nil), "CGameNotifications_GetSessionDetails_Response") | ||||
| 	proto.RegisterType((*GameNotificationSettings)(nil), "GameNotificationSettings") | ||||
| 	proto.RegisterType((*CGameNotifications_UpdateNotificationSettings_Request)(nil), "CGameNotifications_UpdateNotificationSettings_Request") | ||||
| 	proto.RegisterType((*CGameNotifications_UpdateNotificationSettings_Response)(nil), "CGameNotifications_UpdateNotificationSettings_Response") | ||||
| 	proto.RegisterType((*CGameNotifications_OnNotificationsRequested_Notification)(nil), "CGameNotifications_OnNotificationsRequested_Notification") | ||||
| 	proto.RegisterType((*CGameNotifications_OnUserStatusChanged_Notification)(nil), "CGameNotifications_OnUserStatusChanged_Notification") | ||||
| } | ||||
|  | ||||
| var gamenotifications_fileDescriptor0 = []byte{ | ||||
| 	// 2245 bytes of a gzipped FileDescriptorProto | ||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xd4, 0x59, 0xcd, 0x8f, 0x1c, 0x47, | ||||
| 	0x15, 0x57, 0xef, 0xec, 0x7a, 0xd7, 0x65, 0x2c, 0x91, 0x0e, 0x12, 0x93, 0xb1, 0xe3, 0xb4, 0x3b, | ||||
| 	0x38, 0xde, 0x8d, 0x77, 0xcb, 0x78, 0x43, 0xfc, 0x01, 0x24, 0xc2, 0xbd, 0x8e, 0x4c, 0x24, 0xb3, | ||||
| 	0x49, 0xbc, 0x9b, 0x60, 0x21, 0xc4, 0xa8, 0xa6, 0xbb, 0x66, 0xa7, 0xb3, 0x3d, 0xdd, 0x43, 0x57, | ||||
| 	0xf5, 0x6e, 0x36, 0x07, 0x82, 0xcc, 0xd7, 0x09, 0x82, 0x48, 0x22, 0x40, 0x48, 0x91, 0x90, 0x50, | ||||
| 	0xc4, 0x81, 0x0b, 0x87, 0x1c, 0x41, 0x48, 0x91, 0x38, 0x72, 0xcc, 0x15, 0xce, 0xfc, 0x15, 0xbc, | ||||
| 	0xfa, 0xec, 0xee, 0x99, 0x1e, 0xef, 0xcc, 0x22, 0x11, 0x71, 0xb1, 0x3c, 0x5d, 0xf5, 0xde, 0xfb, | ||||
| 	0xd5, 0x7b, 0xbf, 0xf7, 0x51, 0xb5, 0xe8, 0x1a, 0xe3, 0x94, 0x0c, 0x87, 0x94, 0x31, 0xb2, 0x47, | ||||
| 	0x59, 0x77, 0x8f, 0x0c, 0x69, 0x9a, 0xf1, 0xb8, 0x1f, 0x87, 0x84, 0xc7, 0x59, 0xca, 0xb0, 0x5c, | ||||
| 	0x0f, 0x93, 0x98, 0xa6, 0x1c, 0x8f, 0xf2, 0x8c, 0x67, 0x9d, 0xf5, 0xba, 0x48, 0x91, 0xc2, 0x6e, | ||||
| 	0x1a, 0x75, 0x7b, 0x84, 0xd1, 0xc9, 0xdd, 0xfe, 0xbf, 0x16, 0xd0, 0xb9, 0xad, 0xbb, 0xa0, 0x76, | ||||
| 	0xbb, 0xaa, 0xb6, 0xfb, 0x06, 0xc9, 0x63, 0xd2, 0x4b, 0xa8, 0xfb, 0x91, 0x83, 0x5a, 0xfb, 0xf4, | ||||
| 	0xa8, 0xed, 0x78, 0xce, 0xea, 0xe9, 0xe0, 0x37, 0xce, 0xc3, 0x8f, 0xdb, 0xef, 0x39, 0xbb, 0x03, | ||||
| 	0xea, 0xa5, 0x20, 0xe3, 0x65, 0x7d, 0x8f, 0xc3, 0xff, 0x0f, 0xf4, 0x6e, 0x2f, 0x4e, 0xe5, 0xef, | ||||
| 	0x24, 0x0b, 0x49, 0x12, 0xbf, 0x4d, 0x23, 0x8f, 0xd3, 0xb7, 0xb8, 0xb7, 0xb1, 0xe1, 0x91, 0xf4, | ||||
| 	0xe8, 0x70, 0x40, 0x73, 0x0a, 0xcb, 0x84, 0x7b, 0x97, 0x8c, 0x80, 0x50, 0x72, 0xc9, 0x8b, 0x99, | ||||
| 	0xd7, 0xcf, 0x8a, 0x34, 0xf2, 0x0e, 0x63, 0x3e, 0xd0, 0x2a, 0xa4, 0x60, 0xcc, 0xe1, 0x53, 0x92, | ||||
| 	0x78, 0x3d, 0xea, 0xb1, 0xa2, 0xc7, 0x78, 0xcc, 0x8b, 0x88, 0xaa, 0x6d, 0x72, 0xd3, 0x5e, 0x7c, | ||||
| 	0x40, 0x53, 0xb0, 0x9e, 0x14, 0xd4, 0xfd, 0xb5, 0x83, 0x96, 0xe4, 0xff, 0xda, 0x0b, 0x12, 0xea, | ||||
| 	0xcf, 0x04, 0xd4, 0x87, 0x12, 0xaa, 0xfc, 0x3c, 0x81, 0x95, 0x67, 0x56, 0x29, 0x9f, 0x86, 0x1c, | ||||
| 	0xbe, 0x8e, 0x12, 0x12, 0x5a, 0x61, 0x63, 0x50, 0xa9, 0xc0, 0x9e, 0xb7, 0x45, 0x52, 0x40, 0xc9, | ||||
| 	0x68, 0xd2, 0x17, 0x20, 0x89, 0x91, 0x97, 0x5e, 0x04, 0x0b, 0xfb, 0x34, 0xc5, 0xfe, 0x4f, 0x5a, | ||||
| 	0xc8, 0x6b, 0x70, 0xf1, 0x3d, 0x63, 0x6a, 0x17, 0x2c, 0xb9, 0xdf, 0x44, 0x4b, 0x72, 0xbb, 0x76, | ||||
| 	0xf4, 0x2d, 0x00, 0xff, 0xfc, 0xed, 0x06, 0x75, 0xca, 0x81, 0x43, 0x32, 0x62, 0xe2, 0x00, 0x02, | ||||
| 	0x53, 0x44, 0x59, 0x9c, 0x03, 0x60, 0xc6, 0xf3, 0x38, 0xdd, 0xc3, 0xee, 0xcf, 0x1d, 0x74, 0xda, | ||||
| 	0x20, 0x64, 0xe0, 0x8c, 0xd6, 0xea, 0x99, 0xcd, 0xf3, 0xf8, 0x11, 0x31, 0x0e, 0xbe, 0x0b, 0xc6, | ||||
| 	0x1e, 0x80, 0xb1, 0x98, 0x71, 0x71, 0x50, 0x2b, 0xac, 0x1c, 0xc7, 0x26, 0x3d, 0x05, 0xd1, 0xac, | ||||
| 	0xec, 0x52, 0xb1, 0x9b, 0x70, 0xa0, 0xc1, 0xf3, 0x53, 0x07, 0x9d, 0xcd, 0x69, 0x1a, 0x41, 0xf4, | ||||
| 	0xa3, 0xae, 0xf0, 0x6a, 0xbb, 0x25, 0x8f, 0x98, 0x81, 0xd5, 0x7d, 0x71, 0x76, 0xcf, 0xac, 0x1a, | ||||
| 	0x1d, 0x39, 0xfd, 0x3e, 0x98, 0xe5, 0xf0, 0x21, 0x21, 0xe9, 0x5e, 0x01, 0x34, 0x5e, 0xf7, 0xc2, | ||||
| 	0x6c, 0x38, 0x4a, 0x28, 0x98, 0x97, 0xc1, 0xb7, 0x41, 0xb4, 0xb8, 0xc4, 0x89, 0xd6, 0xbd, 0xb8, | ||||
| 	0x2f, 0x62, 0xa0, 0x85, 0xbc, 0x43, 0xc2, 0x3c, 0x36, 0xa2, 0xa1, 0x4c, 0x00, 0xec, 0x7f, 0xb0, | ||||
| 	0x88, 0x9e, 0x6c, 0x70, 0xc3, 0xeb, 0x8c, 0xe6, 0x3b, 0x9c, 0xf0, 0x82, 0xb9, 0xd7, 0xd0, 0xb2, | ||||
| 	0xcc, 0x90, 0x38, 0x92, 0x61, 0x38, 0x15, 0x78, 0x80, 0xf1, 0xbc, 0xa0, 0x90, 0x56, 0x13, 0x7a, | ||||
| 	0x05, 0xec, 0xbe, 0x0c, 0x6a, 0xd5, 0x36, 0xec, 0xfe, 0x01, 0x68, 0xc7, 0x40, 0xda, 0xd0, 0xee, | ||||
| 	0x7d, 0x41, 0xbb, 0x77, 0x25, 0xed, 0xec, 0x56, 0x58, 0x05, 0xaa, 0xe4, 0x94, 0x44, 0x47, 0x22, | ||||
| 	0x17, 0xb8, 0x5e, 0x13, 0xbc, 0x57, 0x1f, 0xc1, 0xc1, 0x40, 0xb3, 0x23, 0xd8, 0x74, 0x48, 0x62, | ||||
| 	0x0e, 0x5e, 0x13, 0xdb, 0x84, 0x0a, 0x91, 0xef, 0x62, 0x9b, 0xf9, 0x9c, 0x09, 0xdf, 0x7b, 0x24, | ||||
| 	0x94, 0x7c, 0xe8, 0xe7, 0xd9, 0xd0, 0x2a, 0xc3, 0xd6, 0x43, 0xd1, 0xba, 0xa2, 0xaa, 0x16, 0xcd, | ||||
| 	0x0e, 0x60, 0xd1, 0xfd, 0x31, 0xc0, 0x04, 0x3f, 0x25, 0x54, 0x3a, 0xff, 0xcc, 0xe6, 0x45, 0x7c, | ||||
| 	0x1c, 0x23, 0x83, 0xfb, 0x70, 0x90, 0xed, 0x5d, 0x21, 0x63, 0xd8, 0xcf, 0xa0, 0xa6, 0x28, 0x22, | ||||
| 	0x7a, 0x51, 0xcc, 0x04, 0x62, 0xc5, 0x41, 0xb0, 0xa2, 0xce, 0x23, 0xc3, 0x17, 0xe7, 0x96, 0x49, | ||||
| 	0x02, 0xe8, 0x81, 0x95, 0x63, 0xd8, 0xfd, 0x95, 0x83, 0x96, 0x75, 0x65, 0x6a, 0x2f, 0xce, 0x0a, | ||||
| 	0xe4, 0x7b, 0x00, 0xe4, 0x3b, 0x3b, 0x45, 0x8f, 0xcf, 0x83, 0x45, 0xfe, 0x53, 0xd6, 0x93, 0x47, | ||||
| 	0x80, 0xf2, 0xdf, 0x5b, 0x42, 0xab, 0x0d, 0x20, 0xb6, 0x20, 0x36, 0x9c, 0xee, 0xa8, 0x6d, 0xdd, | ||||
| 	0xfb, 0x8a, 0x93, 0xee, 0x0d, 0xb4, 0x44, 0x46, 0x23, 0x4d, 0x90, 0xb3, 0xc1, 0x2a, 0x60, 0xfb, | ||||
| 	0x92, 0x88, 0x94, 0xfc, 0x28, 0x20, 0x84, 0x52, 0xac, 0x86, 0xb1, 0x9f, 0x41, 0x04, 0xde, 0x41, | ||||
| 	0xcb, 0x61, 0x96, 0x4a, 0xfe, 0x0b, 0xa6, 0x2c, 0x06, 0x29, 0x88, 0xbe, 0x29, 0xcc, 0x6e, 0x58, | ||||
| 	0x8e, 0x7a, 0x7a, 0x87, 0xae, 0x58, 0x36, 0x8c, 0x21, 0x04, 0x1d, 0x0e, 0x24, 0xf5, 0x13, 0xc6, | ||||
| 	0xb2, 0x30, 0x1e, 0x37, 0x21, 0xb3, 0x82, 0x65, 0xa2, 0x24, 0xf7, 0xde, 0xa4, 0x21, 0x17, 0x4c, | ||||
| 	0x51, 0xc7, 0xee, 0x91, 0x10, 0xca, 0x06, 0x30, 0xf5, 0x47, 0xf3, 0x53, 0xe0, 0x35, 0x80, 0xf8, | ||||
| 	0x2d, 0x71, 0xba, 0x69, 0xae, 0x87, 0x9a, 0xa7, 0xbd, 0x4f, 0x6d, 0xf5, 0xa6, 0x24, 0x1c, 0x18, | ||||
| 	0xee, 0x1b, 0x9f, 0x97, 0x0c, 0x20, 0x68, 0x49, 0xac, 0x31, 0x08, 0xbf, 0x28, 0x4c, 0x17, 0xf0, | ||||
| 	0x23, 0x33, 0x32, 0xd8, 0x04, 0x04, 0x58, 0x20, 0x88, 0x53, 0xc8, 0x00, 0x92, 0xa8, 0x6c, 0x92, | ||||
| 	0x61, 0x84, 0xbe, 0x20, 0x35, 0x99, 0xaa, 0xa1, 0x6d, 0x60, 0xf7, 0x13, 0xa7, 0x4c, 0xe3, 0x25, | ||||
| 	0x99, 0xc6, 0x7f, 0x16, 0x49, 0xf9, 0x27, 0x67, 0xf5, 0x95, 0x91, 0x30, 0x40, 0x92, 0x35, 0x93, | ||||
| 	0xbf, 0xe2, 0x0c, 0x43, 0xb2, 0x4f, 0xab, 0x65, 0x47, 0xb8, 0xae, 0x47, 0x07, 0x04, 0x4a, 0x3a, | ||||
| 	0x98, 0x81, 0x44, 0x84, 0xa2, 0x62, 0x23, 0xb4, 0x5e, 0x66, 0xef, 0xb0, 0x80, 0xbd, 0x3d, 0x3a, | ||||
| 	0x66, 0x1e, 0xf2, 0x33, 0xaa, 0x60, 0xeb, 0x51, 0x91, 0xb6, 0x24, 0x8a, 0x54, 0xf0, 0xaa, 0x1b, | ||||
| 	0x8d, 0x7c, 0x3f, 0x87, 0x76, 0x1c, 0xb1, 0xb2, 0xab, 0xc9, 0x74, 0xf6, 0x63, 0xb4, 0x36, 0x03, | ||||
| 	0x29, 0xd9, 0x08, 0xbe, 0x52, 0xf7, 0xeb, 0xe8, 0xb4, 0x56, 0xab, 0x99, 0xb9, 0x18, 0xac, 0xc1, | ||||
| 	0x91, 0x2f, 0xed, 0x96, 0xf6, 0xe0, 0xb0, 0x3a, 0x7e, 0x8a, 0xa1, 0x91, 0x75, 0x98, 0xff, 0xee, | ||||
| 	0x42, 0x63, 0x02, 0xdc, 0xa1, 0xa2, 0x9c, 0x8c, 0x27, 0xc0, 0xd5, 0x49, 0x53, 0xe7, 0xc1, 0x54, | ||||
| 	0xbb, 0x6e, 0x4a, 0xa4, 0xa5, 0x14, 0xc7, 0xee, 0x75, 0x93, 0x31, 0x0b, 0x32, 0x63, 0x2e, 0xc3, | ||||
| 	0xe6, 0xa7, 0xcb, 0x8c, 0x69, 0x48, 0x67, 0x2d, 0xf7, 0x76, 0x19, 0xc5, 0x96, 0x8c, 0x62, 0x0c, | ||||
| 	0x92, 0xf4, 0x7f, 0x11, 0x43, 0xec, 0x5f, 0x69, 0x74, 0xfe, 0xb8, 0x43, 0x94, 0xf3, 0xfd, 0xbf, | ||||
| 	0x34, 0xd7, 0x8f, 0xd7, 0x47, 0x11, 0xf9, 0x2f, 0xdc, 0x57, 0x48, 0xf1, 0xf9, 0xdd, 0x67, 0xe4, | ||||
| 	0x7e, 0x39, 0x7f, 0xba, 0xcb, 0x42, 0x5b, 0x71, 0xb0, 0x1c, 0xf3, 0xe8, 0x61, 0x63, 0xf6, 0x43, | ||||
| 	0xaf, 0x7a, 0xb9, 0xef, 0xc1, 0x2c, 0x3a, 0xee, 0x57, 0xb5, 0x59, 0x8e, 0x6d, 0x62, 0x15, 0x9c, | ||||
| 	0x1b, 0x0e, 0xa0, 0x21, 0x43, 0x03, 0x76, 0xff, 0xe1, 0xcc, 0x97, 0xfc, 0x1f, 0x8a, 0xb4, 0xfd, | ||||
| 	0x6d, 0x35, 0x6d, 0xcb, 0x21, 0x45, 0xa5, 0xd7, 0xe1, 0x20, 0x63, 0x54, 0xd7, 0x04, 0x33, 0x29, | ||||
| 	0x2a, 0x07, 0x48, 0x1f, 0xe6, 0xb4, 0x9f, 0x88, 0x62, 0x58, 0x8e, 0x6e, 0xba, 0x19, 0xbf, 0xdc, | ||||
| 	0xb7, 0x1c, 0x60, 0x1e, 0x81, 0xb1, 0x54, 0x40, 0x25, 0x89, 0xea, 0xc6, 0x75, 0x32, 0xc8, 0x53, | ||||
| 	0x1d, 0x59, 0xed, 0x36, 0x95, 0x63, 0x5e, 0xaf, 0x34, 0xa7, 0xfe, 0x6f, 0x2b, 0x4d, 0x33, 0xd9, | ||||
| 	0xc7, 0xe9, 0xab, 0xc9, 0xfe, 0xfb, 0x45, 0xb4, 0xde, 0xb0, 0xfb, 0xa5, 0xb4, 0x18, 0xd2, 0xbc, | ||||
| 	0x14, 0x60, 0x96, 0xf0, 0x3f, 0xa8, 0x37, 0x4c, 0x35, 0xf5, 0x8d, 0x93, 0xdd, 0x38, 0x24, 0xa2, | ||||
| 	0x9c, 0xc4, 0x09, 0x93, 0x1d, 0xd3, 0x33, 0x3e, 0xc4, 0x0d, 0x4c, 0x13, 0xe7, 0xe6, 0x95, 0x19, | ||||
| 	0x4b, 0x5b, 0xb5, 0x61, 0xca, 0x29, 0x2f, 0xf2, 0x54, 0x90, 0xee, 0x17, 0x0e, 0x7a, 0x22, 0x4e, | ||||
| 	0xc3, 0x04, 0x6e, 0x0e, 0x5d, 0x90, 0xea, 0x0a, 0x89, 0xae, 0xb9, 0x1d, 0xc9, 0xdc, 0x58, 0x09, | ||||
| 	0xf6, 0x01, 0xd4, 0x5e, 0x25, 0x66, 0x41, 0x96, 0x25, 0x14, 0x7a, 0x2e, 0xc0, 0xa1, 0xf9, 0x10, | ||||
| 	0x5a, 0x0f, 0x78, 0x16, 0xae, 0x2f, 0x60, 0x30, 0x97, 0x56, 0xb5, 0xb8, 0x80, 0x59, 0x89, 0x00, | ||||
| 	0x1b, 0x64, 0x45, 0x12, 0xa9, 0x40, 0x49, 0x7b, 0x11, 0xf6, 0xee, 0xd0, 0x3e, 0x29, 0x12, 0x2e, | ||||
| 	0x67, 0xe8, 0x3e, 0x49, 0xe0, 0x0a, 0xe6, 0xfe, 0xae, 0x0a, 0xa8, 0xe0, 0x83, 0x1a, 0x22, 0x39, | ||||
| 	0x15, 0xad, 0x04, 0x6f, 0x01, 0x20, 0x7e, 0x42, 0x40, 0xe2, 0xb7, 0xd0, 0x0b, 0x77, 0x3c, 0x11, | ||||
| 	0x1e, 0xa0, 0x83, 0x24, 0xd1, 0x8c, 0xe8, 0x02, 0xb4, 0x62, 0xe6, 0x67, 0xd9, 0x3c, 0x4f, 0x07, | ||||
| 	0x5f, 0x06, 0x2c, 0xeb, 0x15, 0x2c, 0xf7, 0xcc, 0x78, 0x0d, 0x42, 0x66, 0xda, 0xaf, 0x5c, 0xd9, | ||||
| 	0xa0, 0x7a, 0x7e, 0xb2, 0x88, 0x3a, 0x0d, 0x1c, 0xd1, 0xd4, 0x80, 0x8a, 0x36, 0x51, 0x02, 0x9f, | ||||
| 	0x06, 0x1b, 0x4f, 0xd5, 0x59, 0xa1, 0x8e, 0x12, 0xb3, 0xb2, 0xaf, 0x6f, 0x54, 0x2b, 0xe1, 0x62, | ||||
| 	0x70, 0x01, 0x64, 0x3a, 0x65, 0x25, 0x34, 0x47, 0xb7, 0xdb, 0x2b, 0x03, 0x57, 0xeb, 0x33, 0x19, | ||||
| 	0xb8, 0x1e, 0x98, 0x02, 0x3c, 0xf3, 0xa4, 0xfb, 0x0c, 0x20, 0xf4, 0xc5, 0x91, 0xc2, 0x22, 0x87, | ||||
| 	0x4b, 0x11, 0xd7, 0xc5, 0x74, 0xe2, 0x68, 0x5f, 0x43, 0x9f, 0xe3, 0xf1, 0x90, 0x76, 0x75, 0x27, | ||||
| 	0x97, 0x81, 0x3a, 0x1b, 0x5c, 0x02, 0xe9, 0x8b, 0x6a, 0x5a, 0x1b, 0x8e, 0x81, 0x85, 0x8b, 0x90, | ||||
| 	0xde, 0x8b, 0xdd, 0x6f, 0x68, 0x61, 0x5d, 0x27, 0x65, 0xe1, 0x3a, 0x1b, 0x3c, 0x0b, 0xc2, 0xcf, | ||||
| 	0x08, 0xe1, 0x84, 0x30, 0xde, 0xac, 0x41, 0x0b, 0x60, 0x37, 0x42, 0x67, 0x24, 0x67, 0x99, 0x2c, | ||||
| 	0xd3, 0xed, 0xe5, 0x99, 0x8a, 0xf9, 0x55, 0x30, 0x70, 0x45, 0x86, 0x58, 0xfe, 0x36, 0x23, 0x5c, | ||||
| 	0x59, 0x86, 0xc7, 0x7b, 0xf0, 0x43, 0x07, 0x6d, 0xcc, 0x58, 0x69, 0xf4, 0x14, 0xf4, 0x1a, 0x5a, | ||||
| 	0x31, 0x85, 0x00, 0x78, 0x25, 0x40, 0x9d, 0xc3, 0xd3, 0x79, 0x18, 0xf8, 0x80, 0xe8, 0x42, 0xd9, | ||||
| 	0x51, 0x1a, 0xca, 0x09, 0xf6, 0x3f, 0x6d, 0x35, 0x96, 0xbb, 0xbb, 0x94, 0x6b, 0x2d, 0x77, 0x54, | ||||
| 	0xc5, 0xb2, 0xe5, 0xee, 0xd5, 0x09, 0x0c, 0x2f, 0xe2, 0x79, 0x14, 0xe0, 0xfb, 0xe6, 0xf2, 0x6b, | ||||
| 	0xd2, 0x05, 0xd7, 0x07, 0x80, 0xa7, 0x00, 0xf5, 0xb9, 0xa9, 0xb4, 0x87, 0x09, 0xfb, 0x46, 0x25, | ||||
| 	0x83, 0xd5, 0x4d, 0x5b, 0x12, 0xe3, 0xd8, 0xb4, 0xed, 0xfc, 0xdb, 0x41, 0x9f, 0x9f, 0xb0, 0x7e, | ||||
| 	0x73, 0x32, 0x59, 0x2d, 0xcf, 0x6a, 0x25, 0x7c, 0x8f, 0xd6, 0xcb, 0xf7, 0x31, 0x75, 0xae, 0xf5, | ||||
| 	0xd9, 0xd6, 0x39, 0xff, 0x9d, 0x46, 0x72, 0x35, 0x85, 0x45, 0x93, 0x6b, 0x7b, 0x3e, 0x72, 0xd9, | ||||
| 	0x30, 0x19, 0x9f, 0x8c, 0x8d, 0x4f, 0xfe, 0x1f, 0x1d, 0xd4, 0x1e, 0x17, 0xdf, 0xa1, 0x5c, 0x5c, | ||||
| 	0xf3, 0xd9, 0xc9, 0x6f, 0x99, 0x3b, 0xe8, 0x71, 0xc8, 0xaa, 0xec, 0xb0, 0x5b, 0x7b, 0x25, 0x94, | ||||
| 	0xd4, 0x59, 0x09, 0xae, 0x83, 0x9a, 0xcd, 0x6f, 0x57, 0xdc, 0x29, 0x1d, 0x26, 0xf7, 0x33, 0xaf, | ||||
| 	0x2a, 0x50, 0x16, 0x5f, 0x30, 0x88, 0xfd, 0x03, 0xf4, 0xfc, 0xd4, 0x01, 0xa1, 0x09, 0xbe, 0x4d, | ||||
| 	0x86, 0x17, 0x50, 0x47, 0x94, 0xd3, 0x1a, 0x98, 0x2e, 0xd3, 0xbb, 0xb4, 0x17, 0x9f, 0xc0, 0xd3, | ||||
| 	0xbc, 0xe0, 0xdf, 0x44, 0xd7, 0xe7, 0xb5, 0xab, 0xa7, 0x94, 0xbf, 0x3b, 0xe8, 0x66, 0x83, 0xe8, | ||||
| 	0x2b, 0x69, 0xed, 0xb7, 0x25, 0x7b, 0xb7, 0xfa, 0x19, 0x22, 0x3d, 0xf6, 0x0a, 0xf4, 0x02, 0xf8, | ||||
| 	0xed, 0x96, 0x99, 0xe3, 0x2a, 0x95, 0x42, 0x8c, 0x9f, 0x35, 0xbf, 0xc1, 0xfc, 0x21, 0xde, 0x38, | ||||
| 	0xcb, 0xf7, 0x2b, 0x19, 0x93, 0xaf, 0xd6, 0x13, 0xf8, 0x0a, 0x68, 0xbb, 0x5c, 0x09, 0xa6, 0x78, | ||||
| 	0xcf, 0x2b, 0x25, 0xea, 0xaf, 0xbb, 0xfe, 0x5f, 0x5b, 0xe8, 0xb9, 0xc6, 0x83, 0x94, 0x95, 0x75, | ||||
| 	0x4b, 0x8d, 0xd7, 0xf5, 0x33, 0xbc, 0x38, 0x7e, 0x86, 0x0d, 0xb0, 0xba, 0x36, 0xe5, 0x0c, 0xcc, | ||||
| 	0x16, 0x65, 0x3b, 0xaa, 0x3f, 0xa8, 0xa6, 0xbd, 0xea, 0xb7, 0x2f, 0x81, 0x86, 0xdb, 0x8d, 0x17, | ||||
| 	0x4a, 0xdb, 0x24, 0xf4, 0x0b, 0x6f, 0xed, 0xe9, 0xab, 0x60, 0xaa, 0xfd, 0x18, 0xcd, 0xf7, 0x8c, | ||||
| 	0x37, 0x5a, 0xd2, 0x1b, 0xd2, 0xb7, 0x53, 0xef, 0x33, 0xd3, 0x34, 0x5a, 0x6d, 0x6f, 0xa0, 0x53, | ||||
| 	0xba, 0x0b, 0xa9, 0x26, 0x7b, 0x5c, 0x17, 0x92, 0x1d, 0xb6, 0x52, 0x70, 0xb6, 0xe1, 0x7a, 0x53, | ||||
| 	0x36, 0x24, 0x3b, 0x13, 0xbb, 0x77, 0xd1, 0x72, 0x4e, 0x87, 0xd9, 0x81, 0x6e, 0xae, 0x3a, 0x77, | ||||
| 	0x2a, 0x82, 0x42, 0xa7, 0x37, 0x20, 0x62, 0xee, 0x86, 0x6b, 0x85, 0xde, 0x5b, 0x3e, 0xc9, 0x99, | ||||
| 	0x34, 0xdf, 0xfc, 0x68, 0x05, 0x3d, 0x36, 0x81, 0x48, 0xbc, 0xd1, 0x3e, 0x26, 0x34, 0xd4, 0xae, | ||||
| 	0xf3, 0xee, 0x1a, 0x9e, 0xf5, 0x19, 0xaa, 0xf3, 0x2c, 0x9e, 0xf9, 0x71, 0xc0, 0xbf, 0x08, 0xd0, | ||||
| 	0x9f, 0x54, 0x6b, 0x4c, 0x3e, 0x1f, 0xb2, 0xa3, 0x34, 0x54, 0x73, 0x8e, 0x86, 0x69, 0xf1, 0xd4, | ||||
| 	0x6e, 0xb8, 0xcd, 0x78, 0x1a, 0x5f, 0x05, 0x9a, 0xf1, 0x4c, 0xb9, 0x2f, 0x4b, 0x3c, 0x6a, 0xed, | ||||
| 	0x38, 0x3c, 0xb5, 0x4b, 0x48, 0x33, 0x9e, 0xc6, 0x6b, 0x76, 0x33, 0x9e, 0x29, 0x57, 0x1a, 0x89, | ||||
| 	0x47, 0xad, 0x4d, 0xc3, 0xf3, 0x3e, 0xe0, 0x99, 0x18, 0x3c, 0xdc, 0x0d, 0x3c, 0xcf, 0x4d, 0xa8, | ||||
| 	0x83, 0xf1, 0x5c, 0xe3, 0x8c, 0x2f, 0x1f, 0x9f, 0xed, 0x3a, 0x40, 0x1b, 0x1f, 0x4f, 0xdc, 0x0f, | ||||
| 	0x01, 0xd6, 0x44, 0xcb, 0x6a, 0x86, 0x35, 0x75, 0xe0, 0x68, 0x86, 0x35, 0xbd, 0x11, 0xfa, 0x72, | ||||
| 	0x52, 0x84, 0x75, 0xfd, 0xc7, 0x07, 0xdb, 0xf1, 0x01, 0x9f, 0x7d, 0x25, 0x37, 0x7e, 0xfb, 0xd4, | ||||
| 	0x41, 0x9d, 0xe9, 0xf5, 0xda, 0xbd, 0x8e, 0x4f, 0xd4, 0x57, 0x3a, 0x37, 0xf0, 0x09, 0xfb, 0xc2, | ||||
| 	0x5d, 0xc0, 0xbe, 0x65, 0x42, 0x6d, 0x06, 0x0b, 0x52, 0xeb, 0x83, 0x32, 0xee, 0xf5, 0xa2, 0x3e, | ||||
| 	0x76, 0x38, 0xa8, 0x54, 0x9d, 0x57, 0x41, 0xd1, 0xbd, 0xdb, 0x70, 0xce, 0xfc, 0x20, 0x0e, 0xd5, | ||||
| 	0x3c, 0xd2, 0x2f, 0xd2, 0x50, 0xed, 0xcf, 0x69, 0x62, 0x5e, 0x20, 0xe4, 0x90, 0x22, 0xf8, 0x94, | ||||
| 	0x67, 0x69, 0x56, 0x34, 0x68, 0x97, 0x2a, 0xa0, 0xe2, 0x6c, 0xfe, 0x73, 0x01, 0x7d, 0x71, 0xe2, | ||||
| 	0x50, 0x5b, 0xf2, 0x4f, 0x75, 0xee, 0x07, 0x30, 0x2b, 0x4c, 0xeb, 0x5d, 0xee, 0x2d, 0x7c, 0xd2, | ||||
| 	0x4e, 0xd7, 0x39, 0x83, 0xb7, 0x33, 0xeb, 0x9b, 0x6b, 0x70, 0xa4, 0x0d, 0xbd, 0x91, 0xa9, 0xb6, | ||||
| 	0x64, 0x9b, 0x44, 0x36, 0x12, 0x23, 0x22, 0x1f, 0xeb, 0x76, 0x22, 0x4d, 0x1f, 0x6f, 0x68, 0x45, | ||||
| 	0xee, 0x57, 0xf0, 0x09, 0x7a, 0x56, 0x1d, 0xcd, 0x73, 0x80, 0xe6, 0x6a, 0x75, 0xb9, 0x8e, 0xa8, | ||||
| 	0x6c, 0x05, 0x83, 0xb2, 0xb9, 0x74, 0xc4, 0x4b, 0xda, 0x17, 0x94, 0xcf, 0xea, 0x48, 0xff, 0xf6, | ||||
| 	0x71, 0x7b, 0x21, 0x68, 0xfd, 0xd0, 0x71, 0xfe, 0x13, 0x00, 0x00, 0xff, 0xff, 0x0c, 0x81, 0x5e, | ||||
| 	0xd6, 0x51, 0x1d, 0x00, 0x00, | ||||
| } | ||||
							
								
								
									
										163
									
								
								vendor/github.com/Philipp15b/go-steam/protocol/protobuf/unified/offline.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										163
									
								
								vendor/github.com/Philipp15b/go-steam/protocol/protobuf/unified/offline.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,163 +0,0 @@ | ||||
| // Code generated by protoc-gen-go. | ||||
| // source: steammessages_offline.steamclient.proto | ||||
| // DO NOT EDIT! | ||||
|  | ||||
| package unified | ||||
|  | ||||
| import proto "github.com/golang/protobuf/proto" | ||||
| import fmt "fmt" | ||||
| import math "math" | ||||
|  | ||||
| // Reference imports to suppress errors if they are not otherwise used. | ||||
| var _ = proto.Marshal | ||||
| var _ = fmt.Errorf | ||||
| var _ = math.Inf | ||||
|  | ||||
| type COffline_GetOfflineLogonTicket_Request struct { | ||||
| 	Priority         *uint32 `protobuf:"varint,1,opt,name=priority" json:"priority,omitempty"` | ||||
| 	XXX_unrecognized []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *COffline_GetOfflineLogonTicket_Request) Reset() { | ||||
| 	*m = COffline_GetOfflineLogonTicket_Request{} | ||||
| } | ||||
| func (m *COffline_GetOfflineLogonTicket_Request) String() string { return proto.CompactTextString(m) } | ||||
| func (*COffline_GetOfflineLogonTicket_Request) ProtoMessage()    {} | ||||
| func (*COffline_GetOfflineLogonTicket_Request) Descriptor() ([]byte, []int) { | ||||
| 	return offline_fileDescriptor0, []int{0} | ||||
| } | ||||
|  | ||||
| func (m *COffline_GetOfflineLogonTicket_Request) GetPriority() uint32 { | ||||
| 	if m != nil && m.Priority != nil { | ||||
| 		return *m.Priority | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type COffline_GetOfflineLogonTicket_Response struct { | ||||
| 	SerializedTicket []byte `protobuf:"bytes,1,opt,name=serialized_ticket" json:"serialized_ticket,omitempty"` | ||||
| 	Signature        []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *COffline_GetOfflineLogonTicket_Response) Reset() { | ||||
| 	*m = COffline_GetOfflineLogonTicket_Response{} | ||||
| } | ||||
| func (m *COffline_GetOfflineLogonTicket_Response) String() string { return proto.CompactTextString(m) } | ||||
| func (*COffline_GetOfflineLogonTicket_Response) ProtoMessage()    {} | ||||
| func (*COffline_GetOfflineLogonTicket_Response) Descriptor() ([]byte, []int) { | ||||
| 	return offline_fileDescriptor0, []int{1} | ||||
| } | ||||
|  | ||||
| func (m *COffline_GetOfflineLogonTicket_Response) GetSerializedTicket() []byte { | ||||
| 	if m != nil { | ||||
| 		return m.SerializedTicket | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *COffline_GetOfflineLogonTicket_Response) GetSignature() []byte { | ||||
| 	if m != nil { | ||||
| 		return m.Signature | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type COffline_GetUnsignedOfflineLogonTicket_Request struct { | ||||
| 	XXX_unrecognized []byte `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *COffline_GetUnsignedOfflineLogonTicket_Request) Reset() { | ||||
| 	*m = COffline_GetUnsignedOfflineLogonTicket_Request{} | ||||
| } | ||||
| func (m *COffline_GetUnsignedOfflineLogonTicket_Request) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*COffline_GetUnsignedOfflineLogonTicket_Request) ProtoMessage() {} | ||||
| func (*COffline_GetUnsignedOfflineLogonTicket_Request) Descriptor() ([]byte, []int) { | ||||
| 	return offline_fileDescriptor0, []int{2} | ||||
| } | ||||
|  | ||||
| type COffline_OfflineLogonTicket struct { | ||||
| 	Accountid           *uint32 `protobuf:"varint,1,opt,name=accountid" json:"accountid,omitempty"` | ||||
| 	Rtime32CreationTime *uint32 `protobuf:"fixed32,2,opt,name=rtime32_creation_time" json:"rtime32_creation_time,omitempty"` | ||||
| 	XXX_unrecognized    []byte  `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *COffline_OfflineLogonTicket) Reset()                    { *m = COffline_OfflineLogonTicket{} } | ||||
| func (m *COffline_OfflineLogonTicket) String() string            { return proto.CompactTextString(m) } | ||||
| func (*COffline_OfflineLogonTicket) ProtoMessage()               {} | ||||
| func (*COffline_OfflineLogonTicket) Descriptor() ([]byte, []int) { return offline_fileDescriptor0, []int{3} } | ||||
|  | ||||
| func (m *COffline_OfflineLogonTicket) GetAccountid() uint32 { | ||||
| 	if m != nil && m.Accountid != nil { | ||||
| 		return *m.Accountid | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (m *COffline_OfflineLogonTicket) GetRtime32CreationTime() uint32 { | ||||
| 	if m != nil && m.Rtime32CreationTime != nil { | ||||
| 		return *m.Rtime32CreationTime | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type COffline_GetUnsignedOfflineLogonTicket_Response struct { | ||||
| 	Ticket           *COffline_OfflineLogonTicket `protobuf:"bytes,1,opt,name=ticket" json:"ticket,omitempty"` | ||||
| 	XXX_unrecognized []byte                       `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *COffline_GetUnsignedOfflineLogonTicket_Response) Reset() { | ||||
| 	*m = COffline_GetUnsignedOfflineLogonTicket_Response{} | ||||
| } | ||||
| func (m *COffline_GetUnsignedOfflineLogonTicket_Response) String() string { | ||||
| 	return proto.CompactTextString(m) | ||||
| } | ||||
| func (*COffline_GetUnsignedOfflineLogonTicket_Response) ProtoMessage() {} | ||||
| func (*COffline_GetUnsignedOfflineLogonTicket_Response) Descriptor() ([]byte, []int) { | ||||
| 	return offline_fileDescriptor0, []int{4} | ||||
| } | ||||
|  | ||||
| func (m *COffline_GetUnsignedOfflineLogonTicket_Response) GetTicket() *COffline_OfflineLogonTicket { | ||||
| 	if m != nil { | ||||
| 		return m.Ticket | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	proto.RegisterType((*COffline_GetOfflineLogonTicket_Request)(nil), "COffline_GetOfflineLogonTicket_Request") | ||||
| 	proto.RegisterType((*COffline_GetOfflineLogonTicket_Response)(nil), "COffline_GetOfflineLogonTicket_Response") | ||||
| 	proto.RegisterType((*COffline_GetUnsignedOfflineLogonTicket_Request)(nil), "COffline_GetUnsignedOfflineLogonTicket_Request") | ||||
| 	proto.RegisterType((*COffline_OfflineLogonTicket)(nil), "COffline_OfflineLogonTicket") | ||||
| 	proto.RegisterType((*COffline_GetUnsignedOfflineLogonTicket_Response)(nil), "COffline_GetUnsignedOfflineLogonTicket_Response") | ||||
| } | ||||
|  | ||||
| var offline_fileDescriptor0 = []byte{ | ||||
| 	// 377 bytes of a gzipped FileDescriptorProto | ||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x52, 0xcd, 0x4a, 0xf3, 0x40, | ||||
| 	0x14, 0x25, 0x5f, 0xe1, 0xab, 0x8e, 0x0a, 0x76, 0xa0, 0x10, 0x63, 0x0b, 0x43, 0x16, 0xb6, 0x8b, | ||||
| 	0x92, 0x96, 0xba, 0x52, 0x70, 0xa3, 0x88, 0x08, 0x42, 0x41, 0x14, 0x97, 0x61, 0x4c, 0x6e, 0xe2, | ||||
| 	0x60, 0x3a, 0x53, 0x67, 0x6e, 0x04, 0x5d, 0x89, 0xaf, 0xe2, 0x33, 0xf4, 0x01, 0x7c, 0x33, 0xf3, | ||||
| 	0x87, 0x56, 0xac, 0xb5, 0xdd, 0x25, 0x37, 0xe7, 0xdc, 0x9c, 0x9f, 0x4b, 0x3a, 0x06, 0x81, 0x8f, | ||||
| 	0xc7, 0x60, 0x0c, 0x8f, 0xc1, 0xf8, 0x2a, 0x8a, 0x12, 0x21, 0xc1, 0x2b, 0xa6, 0x41, 0x22, 0x40, | ||||
| 	0xa2, 0x37, 0xd1, 0x0a, 0x95, 0xd3, 0xfb, 0x0e, 0x4c, 0xa5, 0x88, 0x04, 0x84, 0xfe, 0x2d, 0x37, | ||||
| 	0x73, 0xd0, 0xee, 0x21, 0xd9, 0x3b, 0x19, 0x95, 0xbb, 0xfc, 0x33, 0xc0, 0xea, 0xf1, 0x42, 0xc5, | ||||
| 	0x4a, 0x5e, 0x89, 0xe0, 0x1e, 0xd0, 0xbf, 0x84, 0x87, 0x14, 0x0c, 0xd2, 0x6d, 0xb2, 0x36, 0xd1, | ||||
| 	0x42, 0x69, 0x81, 0x4f, 0xb6, 0xc5, 0xac, 0xee, 0x96, 0x7b, 0x43, 0x3a, 0x7f, 0x72, 0xcd, 0x44, | ||||
| 	0x49, 0x03, 0x74, 0x87, 0x34, 0x0c, 0x68, 0xc1, 0x13, 0xf1, 0x9c, 0x69, 0xc1, 0xe2, 0x6b, 0xb1, | ||||
| 	0x65, 0x93, 0x36, 0xc8, 0xba, 0x11, 0xb1, 0xe4, 0x98, 0x6a, 0xb0, 0xff, 0xe5, 0x23, 0x77, 0x40, | ||||
| 	0xbc, 0xd9, 0xc5, 0xd7, 0x32, 0x07, 0x40, 0xf8, 0xbb, 0x38, 0x77, 0x44, 0x76, 0x3f, 0x19, 0x3f, | ||||
| 	0x61, 0xf9, 0x3f, 0x78, 0x10, 0xa8, 0x54, 0xa2, 0x08, 0x4b, 0xf1, 0xb4, 0x4d, 0x9a, 0x1a, 0xc5, | ||||
| 	0x18, 0xf6, 0x87, 0x7e, 0xa0, 0x81, 0xa3, 0x50, 0xd2, 0xcf, 0xdf, 0x0b, 0x09, 0x75, 0xd7, 0x27, | ||||
| 	0xfd, 0xa5, 0x25, 0x54, 0x1e, 0x7b, 0xe4, 0xff, 0x8c, 0xb1, 0x8d, 0x61, 0xcb, 0x5b, 0x20, 0x69, | ||||
| 	0xf8, 0x56, 0x23, 0xf5, 0x6a, 0x4c, 0xa7, 0x16, 0x69, 0xce, 0x0d, 0x90, 0x76, 0xbc, 0xe5, 0xda, | ||||
| 	0x71, 0xba, 0xde, 0x92, 0x55, 0xb8, 0xe7, 0xaf, 0x53, 0xfb, 0x34, 0xc3, 0x30, 0xce, 0xbe, 0x2a, | ||||
| 	0x61, 0x5c, 0x86, 0xac, 0xb4, 0xc8, 0xaa, 0xd3, 0x62, 0x49, 0xce, 0x66, 0xa5, 0x25, 0x16, 0x29, | ||||
| 	0xcd, 0xf0, 0x0e, 0x58, 0x90, 0x6a, 0x9d, 0x5d, 0x0f, 0x4b, 0x33, 0x2e, 0x7d, 0xb7, 0x48, 0x7b, | ||||
| 	0x61, 0x38, 0xb4, 0xbf, 0x62, 0x91, 0xce, 0xc0, 0x5b, 0x31, 0x76, 0xf7, 0x28, 0xf3, 0x73, 0x50, | ||||
| 	0xf8, 0x91, 0x2c, 0x95, 0xab, 0x7a, 0x70, 0x5a, 0x19, 0xdd, 0xae, 0xf6, 0x67, 0x81, 0x20, 0x0a, | ||||
| 	0x19, 0x9b, 0x3c, 0x99, 0x47, 0x11, 0xc0, 0x71, 0xed, 0xc5, 0xb2, 0x3e, 0x02, 0x00, 0x00, 0xff, | ||||
| 	0xff, 0x90, 0xd3, 0xb5, 0xf7, 0x7b, 0x03, 0x00, 0x00, | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user