Browse Source

Implement message-ids draft

tags/v0.6.0
Daniel Oaks 7 years ago
parent
commit
e741c1476b
6 changed files with 65 additions and 41 deletions
  1. 2
    0
      irc/capability.go
  2. 21
    24
      irc/channel.go
  3. 12
    4
      irc/client.go
  4. 1
    1
      irc/monitor.go
  5. 26
    12
      irc/server.go
  6. 3
    0
      oragono.go

+ 2
- 0
irc/capability.go View File

@@ -23,6 +23,7 @@ const (
23 23
 	ExtendedJoin    Capability = "extended-join"
24 24
 	InviteNotify    Capability = "invite-notify"
25 25
 	MaxLine         Capability = "draft/maxline"
26
+	MessageIDs      Capability = "draft/message-ids"
26 27
 	MessageTags     Capability = "draft/message-tags-0.2"
27 28
 	MultiPrefix     Capability = "multi-prefix"
28 29
 	SASL            Capability = "sasl"
@@ -40,6 +41,7 @@ var (
40 41
 		EchoMessage:   true,
41 42
 		ExtendedJoin:  true,
42 43
 		InviteNotify:  true,
44
+		MessageIDs:    true,
43 45
 		// MaxLine is set during server startup
44 46
 		MessageTags: true,
45 47
 		MultiPrefix: true,

+ 21
- 24
irc/channel.go View File

@@ -372,21 +372,21 @@ func (channel *Channel) CanSpeak(client *Client) bool {
372 372
 }
373 373
 
374 374
 // TagMsg sends a tag message to everyone in this channel who can accept them.
375
-func (channel *Channel) TagMsg(minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client) {
376
-	channel.sendMessage("TAGMSG", []Capability{MessageTags}, minPrefix, clientOnlyTags, client, nil)
375
+func (channel *Channel) TagMsg(msgid string, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client) {
376
+	channel.sendMessage(msgid, "TAGMSG", []Capability{MessageTags}, minPrefix, clientOnlyTags, client, nil)
377 377
 }
378 378
 
379 379
 // PrivMsg sends a private message to everyone in this channel.
380
-func (channel *Channel) PrivMsg(minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message string) {
381
-	channel.sendMessage("PRIVMSG", nil, minPrefix, clientOnlyTags, client, &message)
380
+func (channel *Channel) PrivMsg(msgid string, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message string) {
381
+	channel.sendMessage(msgid, "PRIVMSG", nil, minPrefix, clientOnlyTags, client, &message)
382 382
 }
383 383
 
384 384
 // Notice sends a private message to everyone in this channel.
385
-func (channel *Channel) Notice(minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message string) {
386
-	channel.sendMessage("NOTICE", nil, minPrefix, clientOnlyTags, client, &message)
385
+func (channel *Channel) Notice(msgid string, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message string) {
386
+	channel.sendMessage(msgid, "NOTICE", nil, minPrefix, clientOnlyTags, client, &message)
387 387
 }
388 388
 
389
-func (channel *Channel) sendMessage(cmd string, requiredCaps []Capability, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *string) {
389
+func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []Capability, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *string) {
390 390
 	if !channel.CanSpeak(client) {
391 391
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
392 392
 		return
@@ -419,33 +419,30 @@ func (channel *Channel) sendMessage(cmd string, requiredCaps []Capability, minPr
419 419
 			continue
420 420
 		}
421 421
 
422
+		var messageTagsToUse *map[string]ircmsg.TagValue
422 423
 		if member.capabilities[MessageTags] {
423
-			if message == nil {
424
-				member.SendFromClient(client, clientOnlyTags, client.nickMaskString, cmd, channel.name)
425
-			} else {
426
-				member.SendFromClient(client, clientOnlyTags, client.nickMaskString, cmd, channel.name, *message)
427
-			}
424
+			messageTagsToUse = clientOnlyTags
425
+		}
426
+
427
+		if message == nil {
428
+			member.SendFromClient(msgid, client, messageTagsToUse, client.nickMaskString, cmd, channel.name)
428 429
 		} else {
429
-			if message == nil {
430
-				member.SendFromClient(client, nil, client.nickMaskString, cmd, channel.name)
431
-			} else {
432
-				member.SendFromClient(client, nil, client.nickMaskString, cmd, channel.name, *message)
433
-			}
430
+			member.SendFromClient(msgid, client, messageTagsToUse, client.nickMaskString, cmd, channel.name, *message)
434 431
 		}
435 432
 	}
436 433
 }
437 434
 
438 435
 // SplitPrivMsg sends a private message to everyone in this channel.
439
-func (channel *Channel) SplitPrivMsg(minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
440
-	channel.sendSplitMessage("PRIVMSG", minPrefix, clientOnlyTags, client, message)
436
+func (channel *Channel) SplitPrivMsg(msgid string, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
437
+	channel.sendSplitMessage(msgid, "PRIVMSG", minPrefix, clientOnlyTags, client, message)
441 438
 }
442 439
 
443 440
 // SplitNotice sends a private message to everyone in this channel.
444
-func (channel *Channel) SplitNotice(minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
445
-	channel.sendSplitMessage("NOTICE", minPrefix, clientOnlyTags, client, message)
441
+func (channel *Channel) SplitNotice(msgid string, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
442
+	channel.sendSplitMessage(msgid, "NOTICE", minPrefix, clientOnlyTags, client, message)
446 443
 }
447 444
 
448
-func (channel *Channel) sendSplitMessage(cmd string, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
445
+func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
449 446
 	if !channel.CanSpeak(client) {
450 447
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
451 448
 		return
@@ -468,9 +465,9 @@ func (channel *Channel) sendSplitMessage(cmd string, minPrefix *ChannelMode, cli
468 465
 			continue
469 466
 		}
470 467
 		if member.capabilities[MessageTags] {
471
-			member.SendSplitMsgFromClient(client, clientOnlyTags, cmd, channel.name, message)
468
+			member.SendSplitMsgFromClient(msgid, client, clientOnlyTags, cmd, channel.name, message)
472 469
 		} else {
473
-			member.SendSplitMsgFromClient(client, nil, cmd, channel.name, message)
470
+			member.SendSplitMsgFromClient(msgid, client, nil, cmd, channel.name, message)
474 471
 		}
475 472
 	}
476 473
 }

+ 12
- 4
irc/client.go View File

@@ -498,19 +498,19 @@ func (client *Client) destroy() {
498 498
 
499 499
 // SendSplitMsgFromClient sends an IRC PRIVMSG/NOTICE coming from a specific client.
500 500
 // Adds account-tag to the line as well.
501
-func (client *Client) SendSplitMsgFromClient(from *Client, tags *map[string]ircmsg.TagValue, command, target string, message SplitMessage) {
501
+func (client *Client) SendSplitMsgFromClient(msgid string, from *Client, tags *map[string]ircmsg.TagValue, command, target string, message SplitMessage) {
502 502
 	if client.capabilities[MaxLine] {
503
-		client.SendFromClient(from, tags, from.nickMaskString, command, target, message.ForMaxLine)
503
+		client.SendFromClient(msgid, from, tags, from.nickMaskString, command, target, message.ForMaxLine)
504 504
 	} else {
505 505
 		for _, str := range message.For512 {
506
-			client.SendFromClient(from, tags, from.nickMaskString, command, target, str)
506
+			client.SendFromClient(msgid, from, tags, from.nickMaskString, command, target, str)
507 507
 		}
508 508
 	}
509 509
 }
510 510
 
511 511
 // SendFromClient sends an IRC line coming from a specific client.
512 512
 // Adds account-tag to the line as well.
513
-func (client *Client) SendFromClient(from *Client, tags *map[string]ircmsg.TagValue, prefix string, command string, params ...string) error {
513
+func (client *Client) SendFromClient(msgid string, from *Client, tags *map[string]ircmsg.TagValue, prefix string, command string, params ...string) error {
514 514
 	// attach account-tag
515 515
 	if client.capabilities[AccountTag] && from.account != &NoAccount {
516 516
 		if tags == nil {
@@ -519,6 +519,14 @@ func (client *Client) SendFromClient(from *Client, tags *map[string]ircmsg.TagVa
519 519
 			(*tags)["account"] = ircmsg.MakeTagValue(from.account.Name)
520 520
 		}
521 521
 	}
522
+	// attach message-id
523
+	if len(msgid) > 0 && client.capabilities[MessageIDs] {
524
+		if tags == nil {
525
+			tags = ircmsg.MakeTags("draft/msgid", msgid)
526
+		} else {
527
+			(*tags)["draft/msgid"] = ircmsg.MakeTagValue(msgid)
528
+		}
529
+	}
522 530
 
523 531
 	return client.Send(tags, prefix, command, params...)
524 532
 }

+ 1
- 1
irc/monitor.go View File

@@ -16,7 +16,7 @@ func (client *Client) alertMonitors() {
16 16
 	for _, mClient := range client.server.monitoring[client.nickCasefolded] {
17 17
 		// don't have to notify ourselves
18 18
 		if &mClient != client {
19
-			mClient.SendFromClient(client, nil, client.server.name, RPL_MONONLINE, mClient.nick, client.nickMaskString)
19
+			mClient.SendFromClient("", client, nil, client.server.name, RPL_MONONLINE, mClient.nick, client.nickMaskString)
20 20
 		}
21 21
 	}
22 22
 }

+ 26
- 12
irc/server.go View File

@@ -12,6 +12,7 @@ import (
12 12
 	"errors"
13 13
 	"fmt"
14 14
 	"log"
15
+	"math/rand"
15 16
 	"net"
16 17
 	"net/http"
17 18
 	"os"
@@ -606,6 +607,11 @@ func (server *Server) wslisten(addr string, tlsMap map[string]*TLSListenConfig)
606 607
 	}()
607 608
 }
608 609
 
610
+// generateMessageID returns a network-unique message ID.
611
+func (server *Server) generateMessageID() string {
612
+	return fmt.Sprintf("%s-%s", strconv.FormatInt(time.Now().UTC().UnixNano(), 10), strconv.FormatInt(rand.Int63(), 10))
613
+}
614
+
609 615
 //
610 616
 // server functionality
611 617
 //
@@ -937,7 +943,8 @@ func privmsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool
937 943
 				client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, targetString, "No such channel")
938 944
 				continue
939 945
 			}
940
-			channel.SplitPrivMsg(lowestPrefix, clientOnlyTags, client, splitMsg)
946
+			msgid := server.generateMessageID()
947
+			channel.SplitPrivMsg(msgid, lowestPrefix, clientOnlyTags, client, splitMsg)
941 948
 		} else {
942 949
 			target, err = CasefoldName(targetString)
943 950
 			user := server.clients.Get(target)
@@ -950,9 +957,10 @@ func privmsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool
950 957
 			if !user.capabilities[MessageTags] {
951 958
 				clientOnlyTags = nil
952 959
 			}
953
-			user.SendSplitMsgFromClient(client, clientOnlyTags, "PRIVMSG", user.nick, splitMsg)
960
+			msgid := server.generateMessageID()
961
+			user.SendSplitMsgFromClient(msgid, client, clientOnlyTags, "PRIVMSG", user.nick, splitMsg)
954 962
 			if client.capabilities[EchoMessage] {
955
-				client.SendFromClient(client, clientOnlyTags, client.nickMaskString, "PRIVMSG", user.nick, message)
963
+				client.SendSplitMsgFromClient(msgid, client, clientOnlyTags, "PRIVMSG", user.nick, splitMsg)
956 964
 			}
957 965
 			if user.flags[Away] {
958 966
 				//TODO(dan): possibly implement cooldown of away notifications to users
@@ -993,7 +1001,9 @@ func tagmsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
993 1001
 				client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, targetString, "No such channel")
994 1002
 				continue
995 1003
 			}
996
-			channel.TagMsg(lowestPrefix, clientOnlyTags, client)
1004
+			msgid := server.generateMessageID()
1005
+
1006
+			channel.TagMsg(msgid, lowestPrefix, clientOnlyTags, client)
997 1007
 		} else {
998 1008
 			target, err = CasefoldName(targetString)
999 1009
 			user := server.clients.Get(target)
@@ -1003,13 +1013,15 @@ func tagmsgHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
1003 1013
 				}
1004 1014
 				continue
1005 1015
 			}
1016
+			msgid := server.generateMessageID()
1017
+
1006 1018
 			// end user can't receive tagmsgs
1007 1019
 			if !user.capabilities[MessageTags] {
1008 1020
 				continue
1009 1021
 			}
1010
-			user.SendFromClient(client, clientOnlyTags, "TAGMSG", user.nick)
1022
+			user.SendFromClient(msgid, client, clientOnlyTags, "TAGMSG", user.nick)
1011 1023
 			if client.capabilities[EchoMessage] {
1012
-				client.SendFromClient(client, clientOnlyTags, "TAGMSG", user.nick)
1024
+				client.SendFromClient(msgid, client, clientOnlyTags, "TAGMSG", user.nick)
1013 1025
 			}
1014 1026
 			if user.flags[Away] {
1015 1027
 				//TODO(dan): possibly implement cooldown of away notifications to users
@@ -1210,7 +1222,7 @@ func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
1210 1222
 		originalHost := client.nickMaskString
1211 1223
 		client.vhost = server.operators[name].Vhost
1212 1224
 		for fClient := range client.Friends(ChgHost) {
1213
-			fClient.SendFromClient(client, nil, originalHost, "CHGHOST", client.username, client.vhost)
1225
+			fClient.SendFromClient("", client, nil, originalHost, "CHGHOST", client.username, client.vhost)
1214 1226
 		}
1215 1227
 		client.updateNickMask()
1216 1228
 	}
@@ -1449,9 +1461,9 @@ func awayHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
1449 1461
 	// dispatch away-notify
1450 1462
 	for friend := range client.Friends(AwayNotify) {
1451 1463
 		if client.flags[Away] {
1452
-			friend.SendFromClient(client, nil, client.nickMaskString, "AWAY", client.awayMessage)
1464
+			friend.SendFromClient("", client, nil, client.nickMaskString, "AWAY", client.awayMessage)
1453 1465
 		} else {
1454
-			friend.SendFromClient(client, nil, client.nickMaskString, "AWAY")
1466
+			friend.SendFromClient("", client, nil, client.nickMaskString, "AWAY")
1455 1467
 		}
1456 1468
 	}
1457 1469
 
@@ -1515,7 +1527,8 @@ func noticeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
1515 1527
 				// errors silently ignored with NOTICE as per RFC
1516 1528
 				continue
1517 1529
 			}
1518
-			channel.SplitNotice(lowestPrefix, clientOnlyTags, client, splitMsg)
1530
+			msgid := server.generateMessageID()
1531
+			channel.SplitNotice(msgid, lowestPrefix, clientOnlyTags, client, splitMsg)
1519 1532
 		} else {
1520 1533
 			target, err := CasefoldName(targetString)
1521 1534
 			if err != nil {
@@ -1530,9 +1543,10 @@ func noticeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
1530 1543
 			if !user.capabilities[MessageTags] {
1531 1544
 				clientOnlyTags = nil
1532 1545
 			}
1533
-			user.SendSplitMsgFromClient(client, clientOnlyTags, "NOTICE", user.nick, splitMsg)
1546
+			msgid := server.generateMessageID()
1547
+			user.SendSplitMsgFromClient(msgid, client, clientOnlyTags, "NOTICE", user.nick, splitMsg)
1534 1548
 			if client.capabilities[EchoMessage] {
1535
-				client.SendFromClient(client, clientOnlyTags, client.nickMaskString, "NOTICE", user.nick, message)
1549
+				client.SendSplitMsgFromClient(msgid, client, clientOnlyTags, "NOTICE", user.nick, splitMsg)
1536 1550
 			}
1537 1551
 		}
1538 1552
 	}

+ 3
- 0
oragono.go View File

@@ -8,7 +8,9 @@ package main
8 8
 import (
9 9
 	"fmt"
10 10
 	"log"
11
+	"math/rand"
11 12
 	"syscall"
13
+	"time"
12 14
 
13 15
 	"github.com/DanielOaks/oragono/irc"
14 16
 	"github.com/DanielOaks/oragono/mkcerts"
@@ -83,6 +85,7 @@ Options:
83 85
 		}
84 86
 	} else if arguments["run"].(bool) {
85 87
 		irc.Log.SetLevel(config.Server.Log)
88
+		rand.Seed(time.Now().UTC().UnixNano())
86 89
 		server := irc.NewServer(configfile, config)
87 90
 		if server == nil {
88 91
 			log.Println("Could not load server")

Loading…
Cancel
Save