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

+ 21
- 24
irc/channel.go View File

372
 }
372
 }
373
 
373
 
374
 // TagMsg sends a tag message to everyone in this channel who can accept them.
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
 // PrivMsg sends a private message to everyone in this channel.
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
 // Notice sends a private message to everyone in this channel.
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
 	if !channel.CanSpeak(client) {
390
 	if !channel.CanSpeak(client) {
391
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
391
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
392
 		return
392
 		return
419
 			continue
419
 			continue
420
 		}
420
 		}
421
 
421
 
422
+		var messageTagsToUse *map[string]ircmsg.TagValue
422
 		if member.capabilities[MessageTags] {
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
 		} else {
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
 // SplitPrivMsg sends a private message to everyone in this channel.
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
 // SplitNotice sends a private message to everyone in this channel.
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
 	if !channel.CanSpeak(client) {
446
 	if !channel.CanSpeak(client) {
450
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
447
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
451
 		return
448
 		return
468
 			continue
465
 			continue
469
 		}
466
 		}
470
 		if member.capabilities[MessageTags] {
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
 		} else {
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
 
498
 
499
 // SendSplitMsgFromClient sends an IRC PRIVMSG/NOTICE coming from a specific client.
499
 // SendSplitMsgFromClient sends an IRC PRIVMSG/NOTICE coming from a specific client.
500
 // Adds account-tag to the line as well.
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
 	if client.capabilities[MaxLine] {
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
 	} else {
504
 	} else {
505
 		for _, str := range message.For512 {
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
 // SendFromClient sends an IRC line coming from a specific client.
511
 // SendFromClient sends an IRC line coming from a specific client.
512
 // Adds account-tag to the line as well.
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
 	// attach account-tag
514
 	// attach account-tag
515
 	if client.capabilities[AccountTag] && from.account != &NoAccount {
515
 	if client.capabilities[AccountTag] && from.account != &NoAccount {
516
 		if tags == nil {
516
 		if tags == nil {
519
 			(*tags)["account"] = ircmsg.MakeTagValue(from.account.Name)
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
 	return client.Send(tags, prefix, command, params...)
531
 	return client.Send(tags, prefix, command, params...)
524
 }
532
 }

+ 1
- 1
irc/monitor.go View File

16
 	for _, mClient := range client.server.monitoring[client.nickCasefolded] {
16
 	for _, mClient := range client.server.monitoring[client.nickCasefolded] {
17
 		// don't have to notify ourselves
17
 		// don't have to notify ourselves
18
 		if &mClient != client {
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
 	"errors"
12
 	"errors"
13
 	"fmt"
13
 	"fmt"
14
 	"log"
14
 	"log"
15
+	"math/rand"
15
 	"net"
16
 	"net"
16
 	"net/http"
17
 	"net/http"
17
 	"os"
18
 	"os"
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
 // server functionality
616
 // server functionality
611
 //
617
 //
937
 				client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, targetString, "No such channel")
943
 				client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, targetString, "No such channel")
938
 				continue
944
 				continue
939
 			}
945
 			}
940
-			channel.SplitPrivMsg(lowestPrefix, clientOnlyTags, client, splitMsg)
946
+			msgid := server.generateMessageID()
947
+			channel.SplitPrivMsg(msgid, lowestPrefix, clientOnlyTags, client, splitMsg)
941
 		} else {
948
 		} else {
942
 			target, err = CasefoldName(targetString)
949
 			target, err = CasefoldName(targetString)
943
 			user := server.clients.Get(target)
950
 			user := server.clients.Get(target)
950
 			if !user.capabilities[MessageTags] {
957
 			if !user.capabilities[MessageTags] {
951
 				clientOnlyTags = nil
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
 			if client.capabilities[EchoMessage] {
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
 			if user.flags[Away] {
965
 			if user.flags[Away] {
958
 				//TODO(dan): possibly implement cooldown of away notifications to users
966
 				//TODO(dan): possibly implement cooldown of away notifications to users
993
 				client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, targetString, "No such channel")
1001
 				client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, targetString, "No such channel")
994
 				continue
1002
 				continue
995
 			}
1003
 			}
996
-			channel.TagMsg(lowestPrefix, clientOnlyTags, client)
1004
+			msgid := server.generateMessageID()
1005
+
1006
+			channel.TagMsg(msgid, lowestPrefix, clientOnlyTags, client)
997
 		} else {
1007
 		} else {
998
 			target, err = CasefoldName(targetString)
1008
 			target, err = CasefoldName(targetString)
999
 			user := server.clients.Get(target)
1009
 			user := server.clients.Get(target)
1003
 				}
1013
 				}
1004
 				continue
1014
 				continue
1005
 			}
1015
 			}
1016
+			msgid := server.generateMessageID()
1017
+
1006
 			// end user can't receive tagmsgs
1018
 			// end user can't receive tagmsgs
1007
 			if !user.capabilities[MessageTags] {
1019
 			if !user.capabilities[MessageTags] {
1008
 				continue
1020
 				continue
1009
 			}
1021
 			}
1010
-			user.SendFromClient(client, clientOnlyTags, "TAGMSG", user.nick)
1022
+			user.SendFromClient(msgid, client, clientOnlyTags, "TAGMSG", user.nick)
1011
 			if client.capabilities[EchoMessage] {
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
 			if user.flags[Away] {
1026
 			if user.flags[Away] {
1015
 				//TODO(dan): possibly implement cooldown of away notifications to users
1027
 				//TODO(dan): possibly implement cooldown of away notifications to users
1210
 		originalHost := client.nickMaskString
1222
 		originalHost := client.nickMaskString
1211
 		client.vhost = server.operators[name].Vhost
1223
 		client.vhost = server.operators[name].Vhost
1212
 		for fClient := range client.Friends(ChgHost) {
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
 		client.updateNickMask()
1227
 		client.updateNickMask()
1216
 	}
1228
 	}
1449
 	// dispatch away-notify
1461
 	// dispatch away-notify
1450
 	for friend := range client.Friends(AwayNotify) {
1462
 	for friend := range client.Friends(AwayNotify) {
1451
 		if client.flags[Away] {
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
 		} else {
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
 				// errors silently ignored with NOTICE as per RFC
1527
 				// errors silently ignored with NOTICE as per RFC
1516
 				continue
1528
 				continue
1517
 			}
1529
 			}
1518
-			channel.SplitNotice(lowestPrefix, clientOnlyTags, client, splitMsg)
1530
+			msgid := server.generateMessageID()
1531
+			channel.SplitNotice(msgid, lowestPrefix, clientOnlyTags, client, splitMsg)
1519
 		} else {
1532
 		} else {
1520
 			target, err := CasefoldName(targetString)
1533
 			target, err := CasefoldName(targetString)
1521
 			if err != nil {
1534
 			if err != nil {
1530
 			if !user.capabilities[MessageTags] {
1543
 			if !user.capabilities[MessageTags] {
1531
 				clientOnlyTags = nil
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
 			if client.capabilities[EchoMessage] {
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
 import (
8
 import (
9
 	"fmt"
9
 	"fmt"
10
 	"log"
10
 	"log"
11
+	"math/rand"
11
 	"syscall"
12
 	"syscall"
13
+	"time"
12
 
14
 
13
 	"github.com/DanielOaks/oragono/irc"
15
 	"github.com/DanielOaks/oragono/irc"
14
 	"github.com/DanielOaks/oragono/mkcerts"
16
 	"github.com/DanielOaks/oragono/mkcerts"
83
 		}
85
 		}
84
 	} else if arguments["run"].(bool) {
86
 	} else if arguments["run"].(bool) {
85
 		irc.Log.SetLevel(config.Server.Log)
87
 		irc.Log.SetLevel(config.Server.Log)
88
+		rand.Seed(time.Now().UTC().UnixNano())
86
 		server := irc.NewServer(configfile, config)
89
 		server := irc.NewServer(configfile, config)
87
 		if server == nil {
90
 		if server == nil {
88
 			log.Println("Could not load server")
91
 			log.Println("Could not load server")

Loading…
Cancel
Save