ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/client.c
(Generate patch)

Comparing:
ircd-hybrid/src/client.c (file contents), Revision 1028 by michael, Sun Nov 8 13:03:38 2009 UTC vs.
ircd-hybrid-8/src/client.c (file contents), Revision 1247 by michael, Sat Oct 1 07:54:24 2011 UTC

# Line 26 | Line 26
26   #include "list.h"
27   #include "client.h"
28   #include "channel_mode.h"
29 #include "common.h"
29   #include "event.h"
30   #include "fdlist.h"
31   #include "hash.h"
32   #include "irc_string.h"
34 #include "sprintf_irc.h"
33   #include "ircd.h"
34   #include "s_gline.h"
35   #include "numeric.h"
# Line 76 | Line 74 | static dlink_node *eac_next;  /* next ab
74  
75   static void check_pings_list(dlink_list *);
76   static void check_unknowns_list(void);
77 < static void ban_them(struct Client *client_p, struct ConfItem *conf);
77 > static void ban_them(struct Client *, struct ConfItem *);
78  
79  
80   /* init_client()
# Line 118 | Line 116 | make_client(struct Client *from)
116  
117    if (from == NULL)
118    {
119 <    client_p->from  = client_p; /* 'from' of local client is self! */
120 <    client_p->since = client_p->lasttime = client_p->firsttime = CurrentTime;
121 <
122 <    client_p->localClient = BlockHeapAlloc(lclient_heap);
119 >    client_p->from                      = client_p; /* 'from' of local client is self! */
120 >    client_p->localClient               = BlockHeapAlloc(lclient_heap);
121 >    client_p->localClient->since        = CurrentTime;
122 >    client_p->localClient->lasttime     = CurrentTime;
123 >    client_p->localClient->firsttime    = CurrentTime;
124      client_p->localClient->registration = REG_INIT;
125 +
126      /* as good a place as any... */
127 <    dlinkAdd(client_p, make_dlink_node(), &unknown_list);
127 >    dlinkAdd(client_p, &client_p->localClient->lclient_node, &unknown_list);
128    }
129    else
130      client_p->from = from; /* 'from' of local client is self! */
# Line 253 | Line 253 | check_pings_list(dlink_list *list)
253        continue;
254      }
255  
256    if (GlobalSetOptions.idletime && IsClient(client_p))
257    {
258      if (!IsExemptKline(client_p) && !IsOper(client_p) &&
259          !IsIdlelined(client_p) &&
260          ((CurrentTime - client_p->localClient->last) > GlobalSetOptions.idletime))
261      {
262        struct ConfItem *conf;
263        struct AccessItem *aconf;
264
265        conf = make_conf_item(KLINE_TYPE);
266        aconf = map_to_conf(conf);
267
268        DupString(aconf->host, client_p->host);
269        DupString(aconf->reason, "idle exceeder");
270        DupString(aconf->user, client_p->username);
271        aconf->hold = CurrentTime + 60;
272        add_temp_line(conf);
273
274        sendto_realops_flags(UMODE_ALL, L_ALL,
275                             "Idle time limit exceeded for %s - temp k-lining",
276                             get_client_name(client_p, HIDE_IP));
277        exit_client(client_p, &me, aconf->reason);
278        continue;
279      }
280    }
281
256      if (!IsRegistered(client_p))
257        ping = CONNECTTIMEOUT, pingwarn = 0;
258      else
259        ping = get_client_ping(client_p, &pingwarn);
260  
261 <    if (ping < CurrentTime - client_p->lasttime)
261 >    if (ping < CurrentTime - client_p->localClient->lasttime)
262      {
263        if (!IsPingSent(client_p))
264        {
# Line 295 | Line 269 | check_pings_list(dlink_list *list)
269           */
270          SetPingSent(client_p);
271          ClearPingWarning(client_p);
272 <        client_p->lasttime = CurrentTime - ping;
272 >        client_p->localClient->lasttime = CurrentTime - ping;
273          sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p));
274        }
275        else
276        {
277 <        if (CurrentTime - client_p->lasttime >= 2 * ping)
277 >        if (CurrentTime - client_p->localClient->lasttime >= 2 * ping)
278          {
279            /*
280             * If the client/server hasn't talked to us in 2*ping seconds
# Line 314 | Line 288 | check_pings_list(dlink_list *list)
288              sendto_realops_flags(UMODE_ALL, L_OPER,
289                                   "No response from %s, closing link",
290                                   get_client_name(client_p, MASK_IP));
291 <            ilog(L_NOTICE, "No response from %s, closing link",
291 >            ilog(LOG_TYPE_IRCD, "No response from %s, closing link",
292                   get_client_name(client_p, HIDE_IP));
293            }
294  
295 <          ircsprintf(scratch, "Ping timeout: %d seconds",
296 <                     (int)(CurrentTime - client_p->lasttime));
295 >          snprintf(scratch, sizeof(scratch), "Ping timeout: %d seconds",
296 >                   (int)(CurrentTime - client_p->localClient->lasttime));
297            exit_client(client_p, &me, scratch);
298          }
299          else if (!IsPingWarning(client_p) && pingwarn > 0 &&
300                   (IsServer(client_p) || IsHandshake(client_p)) &&
301 <                 CurrentTime - client_p->lasttime >= ping + pingwarn)
301 >                 CurrentTime - client_p->localClient->lasttime >= ping + pingwarn)
302          {
303            /*
304             * If the server hasn't replied in pingwarn seconds after sending
# Line 337 | Line 311 | check_pings_list(dlink_list *list)
311            sendto_realops_flags(UMODE_ALL, L_OPER,
312                                 "Warning, no response from %s in %d seconds",
313                                 get_client_name(client_p, MASK_IP), pingwarn);
314 <          ilog(L_NOTICE, "No response from %s in %d seconds",
314 >          ilog(LOG_TYPE_IRCD, "No response from %s in %d seconds",
315                 get_client_name(client_p, HIDE_IP), pingwarn);
316          }
317        }
# Line 371 | Line 345 | check_unknowns_list(void)
345       * Check UNKNOWN connections - if they have been in this state
346       * for > 30s, close them.
347       */
348 <    if (IsAuthFinished(client_p) && (CurrentTime - client_p->firsttime) > 30)
348 >    if (IsAuthFinished(client_p) && (CurrentTime - client_p->localClient->firsttime) > 30)
349        exit_client(client_p, &me, "Registration timed out");
350    }
351   }
# Line 554 | Line 528 | ban_them(struct Client *client_p, struct
528   static void
529   update_client_exit_stats(struct Client *client_p)
530   {
531 <  if (IsServer(client_p))
558 <  {
559 <    sendto_realops_flags(UMODE_EXTERNAL, L_ALL, "Server %s split from %s",
560 <                         client_p->name, client_p->servptr->name);
561 <  }
562 <  else if (IsClient(client_p))
531 >  if (IsClient(client_p))
532    {
533      assert(Count.total > 0);
534      --Count.total;
535 <    if (IsOper(client_p))
535 >    if (HasUMode(client_p, UMODE_OPER))
536        --Count.oper;
537 <    if (IsInvisible(client_p))
537 >    if (HasUMode(client_p, UMODE_INVISIBLE))
538        --Count.invisi;
539    }
540 +  else if (IsServer(client_p))
541 +    sendto_realops_flags(UMODE_EXTERNAL, L_ALL, "Server %s split from %s",
542 +                         client_p->name, client_p->servptr->name);
543  
544    if (splitchecking && !splitmode)
545      check_splitmode(NULL);
# Line 590 | Line 562 | find_person(const struct Client *client_
562      if ((c2ptr = hash_find_id(name)) != NULL)
563      {
564        /* invisible users shall not be found by UID guessing */
565 <      if (IsInvisible(c2ptr) && !IsServer(client_p))
565 >      if (HasUMode(c2ptr, UMODE_INVISIBLE) && !IsServer(client_p))
566          c2ptr = NULL;
567      }
568    }
569    else
570 <    c2ptr = find_client(name);
570 >    c2ptr = hash_find_client(name);
571  
572    return ((c2ptr != NULL && IsClient(c2ptr)) ? c2ptr : NULL);
573   }
# Line 615 | Line 587 | find_chasing(struct Client *client_p, st
587      *chasing = 0;
588  
589    if (who)
590 <    return(who);
590 >    return who;
591  
592    if (IsDigit(*user))
593 <    return(NULL);
593 >    return NULL;
594  
595    if ((who = get_history(user,
596                          (time_t)ConfigFileEntry.kill_chase_time_limit))
# Line 626 | Line 598 | find_chasing(struct Client *client_p, st
598    {
599      sendto_one(source_p, form_str(ERR_NOSUCHNICK),
600                 me.name, source_p->name, user);
601 <    return(NULL);
601 >    return NULL;
602    }
603  
604    if (chasing)
605      *chasing = 1;
606  
607 <  return(who);
607 >  return who;
608   }
609  
610   /*
# Line 654 | Line 626 | find_chasing(struct Client *client_p, st
626   *        to modify what it points!!!
627   */
628   const char *
629 < get_client_name(struct Client *client, int showip)
629 > get_client_name(const struct Client *client, int showip)
630   {
631    static char nbuf[HOSTLEN * 2 + USERLEN + 5];
632  
633    assert(client != NULL);
634  
635    if (irccmp(client->name, client->host) == 0)
636 <    return(client->name);
636 >    return client->name;
637  
638    if (ConfigServerHide.hide_server_ips)
639      if (IsServer(client) || IsConnecting(client) || IsHandshake(client))
# Line 677 | Line 649 | get_client_name(struct Client *client, i
649      case SHOW_IP:
650        if (MyConnect(client))
651        {
652 <        ircsprintf(nbuf, "%s[%s@%s]", client->name, client->username,
653 <                   client->sockhost);
652 >        snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
653 >                 client->name,
654 >                 client->username, client->sockhost);
655          break;
656        }
657      case MASK_IP:
658 <      ircsprintf(nbuf, "%s[%s@255.255.255.255]", client->name,
659 <                 client->username);
658 >      snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
659 >               client->name, client->username);
660        break;
661      default:
662 <      ircsprintf(nbuf, "%s[%s@%s]", client->name, client->username,
663 <                 client->host);
662 >      snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
663 >               client->name,
664 >               client->username, client->host);
665    }
666  
667 <  return(nbuf);
667 >  return nbuf;
668   }
669  
670   void
# Line 719 | Line 693 | exit_one_client(struct Client *source_p,
693  
694    assert(!IsMe(source_p));
695  
696 <  if (IsServer(source_p))
723 <  {
724 <    dlinkDelete(&source_p->lnode, &source_p->servptr->serv->server_list);
725 <
726 <    if ((lp = dlinkFindDelete(&global_serv_list, source_p)) != NULL)
727 <      free_dlink_node(lp);
728 <  }
729 <  else if (IsClient(source_p))
696 >  if (IsClient(source_p))
697    {
698      if (source_p->servptr->serv != NULL)
699        dlinkDelete(&source_p->lnode, &source_p->servptr->serv->client_list);
700  
701 <    /* If a person is on a channel, send a QUIT notice
702 <    ** to every client (person) on the same channel (so
703 <    ** that the client can show the "**signoff" message).
704 <    ** (Note: The notice is to the local clients *only*)
705 <    */
701 >    /*
702 >     * If a person is on a channel, send a QUIT notice
703 >     * to every client (person) on the same channel (so
704 >     * that the client can show the "**signoff" message).
705 >     * (Note: The notice is to the local clients *only*)
706 >     */
707      sendto_common_channels_local(source_p, 0, ":%s!%s@%s QUIT :%s",
708                                   source_p->name, source_p->username,
709                                   source_p->host, quitmsg);
# Line 756 | Line 724 | exit_one_client(struct Client *source_p,
724        del_all_accepts(source_p);
725      }
726    }
727 +  else if (IsServer(source_p))
728 +  {
729 +    dlinkDelete(&source_p->lnode, &source_p->servptr->serv->server_list);
730 +
731 +    if ((lp = dlinkFindDelete(&global_serv_list, source_p)) != NULL)
732 +      free_dlink_node(lp);
733 +  }
734  
735    /* Remove source_p from the client lists */
736    if (HasID(source_p))
# Line 795 | Line 770 | exit_one_client(struct Client *source_p,
770   static void
771   recurse_send_quits(struct Client *original_source_p, struct Client *source_p,
772                     struct Client *from, struct Client *to, const char *comment,
773 <                   const char *splitstr, const char *myname)
773 >                   const char *splitstr)
774   {
775    dlink_node *ptr, *next;
776    struct Client *target_p;
777 <  int hidden = match(myname, source_p->name);
777 >  int hidden = match(me.name, source_p->name); /* XXX */
778  
779    assert(to != source_p);  /* should be already removed from serv_list */
780  
# Line 818 | Line 793 | recurse_send_quits(struct Client *origin
793  
794    DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head)
795      recurse_send_quits(original_source_p, ptr->data, from, to,
796 <                       comment, splitstr, myname);
796 >                       comment, splitstr);
797  
798    if (!hidden && ((source_p == original_source_p && to != from) ||
799                    !IsCapable(to, CAP_QS)))
# Line 859 | Line 834 | static void
834   remove_dependents(struct Client *source_p, struct Client *from,
835                    const char *comment, const char *splitstr)
836   {
837 <  struct Client *to;
863 <  struct ConfItem *conf;
864 <  static char myname[HOSTLEN+1];
865 <  dlink_node *ptr;
837 >  dlink_node *ptr = NULL;
838  
839    DLINK_FOREACH(ptr, serv_list.head)
840 <  {
841 <    to = ptr->data;
870 <
871 <    if ((conf = to->serv->sconf) != NULL)
872 <      strlcpy(myname, my_name_for_link(conf), sizeof(myname));
873 <    else
874 <      strlcpy(myname, me.name, sizeof(myname));
875 <    recurse_send_quits(source_p, source_p, from, to,
876 <                       comment, splitstr, myname);
877 <  }
840 >    recurse_send_quits(source_p, source_p, from, ptr->data,
841 >                       comment, splitstr);
842  
843    recurse_remove_clients(source_p, splitstr);
844   }
# Line 884 | Line 848 | remove_dependents(struct Client *source_
848   * this on any struct Client, regardless of its state.
849   *
850   * Note, you shouldn't exit remote _users_ without first doing
851 < * SetKilled and propagating a kill or similar message. However,
852 < * it is perfectly correct to call exit_client to force a _server_
851 > * AddFlag(x, FLAGS_KILLED) and propagating a kill or similar message.
852 > * However, it is perfectly correct to call exit_client to force a _server_
853   * quit (either local or remote one).
854   *
855   * inputs:       - a client pointer that is going to be exited
# Line 900 | Line 864 | remove_dependents(struct Client *source_
864   void
865   exit_client(struct Client *source_p, struct Client *from, const char *comment)
866   {
867 <  dlink_node *m;
867 >  dlink_node *m = NULL;
868  
869    if (MyConnect(source_p))
870    {
# Line 929 | Line 893 | exit_client(struct Client *source_p, str
893       */
894      if (!IsRegistered(source_p))
895      {
896 <      if ((m = dlinkFindDelete(&unknown_list, source_p)) != NULL)
897 <        free_dlink_node(m);
896 >      assert(dlinkFind(&unknown_list, source_p));
897 >
898 >      dlinkDelete(&source_p->localClient->lclient_node, &unknown_list);
899      }
900      else if (IsClient(source_p))
901      {
902 +      time_t on_for = CurrentTime - source_p->localClient->firsttime;
903        assert(Count.local > 0);
904        Count.local--;
905  
906 <      if (IsOper(source_p))
906 >      if (HasUMode(source_p, UMODE_OPER))
907        {
908          if ((m = dlinkFindDelete(&oper_list, source_p)) != NULL)
909            free_dlink_node(m);
910        }
911  
912 +      assert(dlinkFind(&local_client_list, source_p));
913        dlinkDelete(&source_p->localClient->lclient_node, &local_client_list);
914 +
915        if (source_p->localClient->list_task != NULL)
916          free_list_task(source_p->localClient->list_task, source_p);
917  
# Line 956 | Line 924 | exit_client(struct Client *source_p, str
924                             source_p->name,
925                             source_p->username,
926                             source_p->host,
959
927                             ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
928                             "255.255.255.255" : source_p->sockhost,
929                             comment);
930 +      ilog(LOG_TYPE_USER, "%s (%3u:%02u:%02u): %s!%s@%s %llu/%llu",
931 +           myctime(source_p->localClient->firsttime), (unsigned int)(on_for / 3600),
932 +           (unsigned int)((on_for % 3600)/60), (unsigned int)(on_for % 60),
933 +           source_p->name, source_p->username, source_p->host,
934 +           source_p->localClient->send.bytes>>10,
935 +           source_p->localClient->recv.bytes>>10);
936      }
937  
938      /* As soon as a client is known to be a server of some sort
939       * it has to be put on the serv_list, or SJOIN's to this new server
940       * from the connect burst will not be seen.
941 +     * XXX - TBV.  This is not true. The only place where we put a server on
942 +     * serv_list is in server_estab right now after registration process.
943 +     * And only after this, a burst is sent to the remote server, i.e. we never
944 +     * send a burst to STAT_CONNECTING, or STAT_HANDSHAKE. This will need
945 +     * more investigation later on, but for now, it's not a problem after all.
946       */
947      if (IsServer(source_p) || IsConnecting(source_p) ||
948          IsHandshake(source_p))
949      {
950 <      if ((m = dlinkFindDelete(&serv_list, source_p)) != NULL)
950 >      if (dlinkFind(&serv_list, source_p))
951        {
952 <        free_dlink_node(m);
952 >        dlinkDelete(&source_p->localClient->lclient_node, &serv_list);
953          unset_chcap_usage_counts(source_p);
954        }
955  
# Line 979 | Line 957 | exit_client(struct Client *source_p, str
957          Count.myserver--;
958      }
959  
982    log_user_exit(source_p);
983
960      if (!IsDead(source_p))
961      {
962        if (IsServer(source_p))
# Line 1031 | Line 1007 | exit_client(struct Client *source_p, str
1007      {
1008        sendto_realops_flags(UMODE_ALL, L_ALL,
1009                             "%s was connected for %d seconds.  %llu/%llu sendK/recvK.",
1010 <                           source_p->name, (int)(CurrentTime - source_p->firsttime),
1010 >                           source_p->name, (int)(CurrentTime - source_p->localClient->firsttime),
1011                             source_p->localClient->send.bytes >> 10,
1012                             source_p->localClient->recv.bytes >> 10);
1013 <      ilog(L_NOTICE, "%s was connected for %d seconds.  %llu/%llu sendK/recvK.",
1014 <           source_p->name, (int)(CurrentTime - source_p->firsttime),
1013 >      ilog(LOG_TYPE_IRCD, "%s was connected for %d seconds.  %llu/%llu sendK/recvK.",
1014 >           source_p->name, (int)(CurrentTime - source_p->localClient->firsttime),
1015             source_p->localClient->send.bytes >> 10,
1016             source_p->localClient->recv.bytes >> 10);
1017      }
1018    }
1019 <  else if (IsClient(source_p) && !IsKilled(source_p))
1019 >  else if (IsClient(source_p) && !HasFlag(source_p, FLAGS_KILLED))
1020    {
1021      sendto_server(from->from, NULL, CAP_TS6, NOCAPS,
1022                    ":%s QUIT :%s", ID(source_p), comment);
# Line 1103 | Line 1079 | dead_link_on_read(struct Client *client_
1079  
1080    if (IsServer(client_p) || IsHandshake(client_p))
1081    {
1082 <    int connected = CurrentTime - client_p->firsttime;
1082 >    int connected = CurrentTime - client_p->localClient->firsttime;
1083        
1084      if (error == 0)
1085      {
# Line 1117 | Line 1093 | dead_link_on_read(struct Client *client_
1093                             "Server %s closed the connection",
1094                             get_client_name(client_p, MASK_IP));
1095  
1096 <      ilog(L_NOTICE, "Server %s closed the connection",
1096 >      ilog(LOG_TYPE_IRCD, "Server %s closed the connection",
1097             get_client_name(client_p, SHOW_IP));
1098      }
1099      else
# Line 1140 | Line 1116 | dead_link_on_read(struct Client *client_
1116      strlcpy(errmsg, "Remote host closed the connection",
1117              sizeof(errmsg));
1118    else
1119 <    ircsprintf(errmsg, "Read error: %s",
1120 <               strerror(current_error));
1119 >    snprintf(errmsg, sizeof(errmsg), "Read error: %s",
1120 >             strerror(current_error));
1121  
1122    exit_client(client_p, &me, errmsg);
1123   }
# Line 1238 | Line 1214 | accept_message(struct Client *source,
1214                                        source->host, target, 1))
1215      return 1;
1216  
1217 <  if (IsSoftCallerId(target))
1217 >  if (HasUMode(target, UMODE_SOFTCALLERID))
1218      DLINK_FOREACH(ptr, target->channel.head)
1219        if (IsMember(source, ((struct Membership *)ptr->data)->chptr))
1220          return 1;
# Line 1260 | Line 1236 | del_all_accepts(struct Client *client_p)
1236    DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->acceptlist.head)
1237      del_accept(ptr->data, client_p);
1238   }
1263
1264 /* change_local_nick()
1265 *
1266 * inputs       - pointer to server
1267 *              - pointer to client
1268 *              - nick
1269 * output       -
1270 * side effects - changes nick of a LOCAL user
1271 */
1272 void
1273 change_local_nick(struct Client *client_p, struct Client *source_p, const char *nick)
1274 {
1275  int samenick = 0;
1276
1277  assert(source_p->name[0] && !EmptyString(nick));
1278
1279  /*
1280   * Client just changing his/her nick. If he/she is
1281   * on a channel, send note of change to all clients
1282   * on that channel. Propagate notice to other servers.
1283   */
1284  if ((source_p->localClient->last_nick_change +
1285       ConfigFileEntry.max_nick_time) < CurrentTime)
1286    source_p->localClient->number_of_nick_changes = 0;
1287  source_p->localClient->last_nick_change = CurrentTime;
1288  source_p->localClient->number_of_nick_changes++;
1289
1290  if ((ConfigFileEntry.anti_nick_flood &&
1291      (source_p->localClient->number_of_nick_changes
1292       <= ConfigFileEntry.max_nick_changes)) ||
1293     !ConfigFileEntry.anti_nick_flood ||
1294     (IsOper(source_p) && ConfigFileEntry.no_oper_flood))
1295  {
1296    samenick = !irccmp(source_p->name, nick);
1297
1298    if (!samenick)
1299    {
1300      source_p->tsinfo = CurrentTime;
1301      clear_ban_cache_client(source_p);
1302      watch_check_hash(source_p, RPL_LOGOFF);
1303    }
1304
1305    /* XXX - the format of this notice should eventually be changed
1306     * to either %s[%s@%s], or even better would be get_client_name() -bill
1307     */
1308    sendto_realops_flags(UMODE_NCHANGE, L_ALL, "Nick change: From %s to %s [%s@%s]",
1309                         source_p->name, nick, source_p->username, source_p->host);
1310    sendto_common_channels_local(source_p, 1, ":%s!%s@%s NICK :%s",
1311                                 source_p->name, source_p->username,
1312                                 source_p->host, nick);
1313    add_history(source_p, 1);
1314
1315    sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
1316                  ":%s NICK %s :%lu",
1317                  ID(source_p), nick, (unsigned long)source_p->tsinfo);
1318    sendto_server(client_p, NULL, NOCAPS, CAP_TS6,
1319                  ":%s NICK %s :%lu",
1320                  source_p->name, nick, (unsigned long)source_p->tsinfo);
1321
1322    hash_del_client(source_p);
1323    strcpy(source_p->name, nick);
1324    hash_add_client(source_p);
1325
1326    if (!samenick)
1327      watch_check_hash(source_p, RPL_LOGON);
1328
1329    /* fd_desc is long enough */
1330    fd_note(&client_p->localClient->fd, "Nick: %s", nick);
1331  }
1332  else
1333    sendto_one(source_p, form_str(ERR_NICKTOOFAST),
1334               me.name, source_p->name, source_p->name,
1335               nick, ConfigFileEntry.max_nick_time);
1336 }

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)