text:
Not from the U.S.? Click here to go to our international version Close
EDITION: U.S.
CNN Trends
THE SITUATION ROOM
Boston Bomber Sentenced to Die; Surprise ISIS Offensive Threatens Key Iraqi City. Aired 5-6:00p ET
Aired May 15, 2015 - 17:00 ET
ANNOUNCER: This is CNN breaking news.
WOLF BLITZER, CNN ANCHOR: I'm Wolf Blitzer in THE SITUATION ROOM. We want to welcome viewers in the United States and around the world. You're watching a live news conference where prosecutors and the FBI are discussing the jury's decision, a death sentence for the Boston Marathon bomber, Dzhokhar Tsarnaev.
Let's continue to listen in.
UNIDENTIFIED FEMALE: ... at which point, victims and survivors will have an opportunity to make an impact statement in writing. We've already solicited impact statements from victims and survivors, but some, obviously, will be given an opportunity to be heard in court, and so we'll figure that out.
But there when be a sentencing hearing. The judge will informally issue a sentence, and -- and then the defendant will go into the custody of the Federal Bureau of Prisons, and then they will determine whether he goes to ADX or he goes to Terre Haute, awaiting the appellate process, but we have nothing to do with that. The Federal Bureau of Prisons will then be in charge.
UNIDENTIFIED MALE: (UNINTELLIGIBLE) to a point that you or law enforcement a particular part of this case, something you that found that really drove you guys to the death penalty -- how do you feel about what (UNINTELLIGIBLE) Tsarnaev's behavior that made him think we need to (UNINTELLIGIBLE)...
UNIDENTIFIED FEMALE: When you look at the crimes that occurred here, the heinous gravity of the crimes, the number of deaths, you know, a child was murdered with a weapon of mass destruction.
Another young -- two young women, as well. A police officer was executed in the line of duty. And so when you look at the gravity of the -- of the harm and in particular, as well, the many, many victims who became amputees and many others who are suffering with other forms of injuries.
And then you look at the motives, as we said in our case, the political motives. Really, this was an act of terrorism. Then that process began, and the Department of Justice approved a path that provided for the severest of punishments, severe punishment for a severe crime. UNIDENTIFIED FEMALE: (UNINTELLIGIBLE)
UNIDENTIFIED FEMALE: I'm sorry.
UNIDENTIFIED FEMALE: And the -- (UNINTELLIGIBLE)focus on the (UNINTELLIGIBLE) I guess can you comment about the death penalty versus a life sentence now that -- (UNINTELLIGIBLE).
UNIDENTIFIED FEMALE: I didn't hear the last part of your question.
UNIDENTIFIED FEMALE: Can you comment? What is your reaction to the jury's finding on the pressure cooker, No. 1, the (UNINTELLIGIBLE) life sentence there versus -- (UNINTELLIGIBLE).
UNIDENTIFIED FEMALE: I'm not -- at this juncture, I'm not going to comment on what you're asking me is really to go into the jury's deliberations. Obviously, they had taken their time. They were deliberate in how they made their findings. Only to say that, as we said, we are gratified with the jury's verdict, and we very much respect how they concluded it. Yes?
UNIDENTIFIED MALE: Massachusetts is known as a fairly liberal district when it comes to the death penalty. Were you confident that they would go for death or are you surprised at it?
UNIDENTIFIED FEMALE: How I feel about it, really isn't at issue here. I think that you make a very good point in terms of the type of state that this is, but you have to realize that when -- when you're in court and you're sitting as jury and you're listening, you're the only ones that really have full access to all of the evidence, all of the key factors that should be considered. You have the law to follow.
I think that that has much more of a controlling factor, rather than what your opinion may be. But clearly, never an easy decision.
What I was confident of and what I think proved true is the tremendous work that the prosecutors and the investigators did in presenting this case. I thought that they, first of all, in terms of the investigation, they left no stone unturned but in terms of the presentation of the evidence, I feel very gratified and very proud that we were able to show exactly what happened here, provide motives for what actually did happen, so that the jury could render a just and fair verdict.
UNIDENTIFIED FEMALE: (UNINTELLIGIBLE).
UNIDENTIFIED FEMALE: Go?
UNIDENTIFIED FEMALE: Were you surprised at all? I mean (UNINTELLIGIBLE) the overall timing, you know, what was mentioned about (UNINTELLIGIBLE) can you -- (UNINTELLIGIBLE).
UNIDENTIFIED FEMALE: I don't want to comment on that.
UNIDENTIFIED FEMALE: Did you...
UNIDENTIFIED FEMALE: About the emotion...
UNIDENTIFIED FEMALE: Michelle?
UNIDENTIFIED FEMALE: (UNINTELLIGIBLE) Very emotional. During the presentation of the evidence, can we hear a little about their reaction today? This was a dogged investigation. Can we hear about their reaction and the victim's reaction after the verdict was rendered?
[17:05:14] UNIDENTIFIED FEMALE: Do you want to hear from -- Phil, do you want to speak? No. We're not going to talk about -- we have had private conversations with victims. We've met with them throughout the process, the very beginning of the trial. I had meeting sessions with them, with the trial team, myself directly. I've personally met with many victims and families. And those conversations are private. What we've tried to do is show support and really try to prepare them for this incredible process.
UNIDENTIFIED FEMALE: They were -- at some point did members of the prosecution team -- an emotionally charged case. What are their reactions? The prosecutors.
UNIDENTIFIED FEMALE: Yes. I think they want to hear -- Bill, why don't you take a stab at it?
BILL WEINREB, PROSECUTOR: OK. Well, on behalf of the prosecution team, I think I can say we feel very privileged to have represented the United States in this case. We're grateful to the U.S. attorney and to the Department of Justice for entrusting us with an important case. And it was our goal to make sure that the jury got all the information they needed to make a fair and impartial decision in this case.
We wanted to make sure the victims had an opportunity to tell their stories, and we wanted to make sure that -- that the entire, the entire story was told. And we are grateful for all the people who assisted us in that endeavor. It's been a long haul.
We think that we, we did our best and we're grateful for the opportunity we had to do that. We're grateful for the jury's hard work in this case, and it is an emotional experience to be part of, but we -- it's part of your job as a prosecutor, to put your emotions aside and follow the law, do what your job requires and that's what we tried to do in this case.
UNIDENTIFIED MALE: ... want to tell the whole story at trial. Is that why you didn't take the -- earlier when they offered -- (UNINTELLIGIBLE).
UNIDENTIFIED MALE: Well, we can't comment on anything that isn't in the public record in this case. But it's always the job of prosecutors and prosecuting a case to try and make sure that the story gets told and that the jury has the information they need to achieve a fair verdict. UNIDENTIFIED FEMALE: Bill, is there an answer in all of this --
yet that you most wish today you knew the answer to?
UNIDENTIFIED FEMALE: You know, the four of us standing up here along with many other people who aren't standing here, but who were every bit as much partners with us in this case, as we were -- have spent the last two years working night and day researching the facts of this case, trying to understand what happened, and I think that we have as full and clear a picture of what happened as we could hope to have.
UNIDENTIFIED MALE: Is there -- (UNINTELLIGIBLE) frustrated (UNINTELLIGIBLE) -- Tsarnaev -- I think a lot of those watching (UNINTELLIGIBLE) do you feel as a prosecutor like you had fair insight into his mind of what happened -- (UNINTELLIGIBLE).
UNIDENTIFIED MALE: Nobody can see into another person's mind. And it's often the case in criminal cases that you have to prove that somebody had an intent to do something or a motive to do something, and you do that in the only way that you can as a prosecutor, which is that you look at the facts, you look at the things that they said, you look at all the evidence in the case, and you present it to the jury, and ultimately, it's for them to make those judgments.
I'm not a mind reader, but you know, our job was to try and -- to try and recognize the facts and the evidence that would help the jury make that decision for themselves, and that's what we tried to do.
UNIDENTIFIED FEMALE: Last question. Last question.
UNIDENTIFIED FEMALE: Mr. Tsarnaev -- showed little or no remorse throughout the entire trial, including today. What does that tell you -- (UNINTELLIGIBLE).
UNIDENTIFIED FEMALE: I'm not going to comment on Mr. Tsarnaev or anything that he did or said or anything like that. That wouldn't be appropriate for me. Again, the issue of remorse was an issue that was put before the jury. They heard evidence about it, and they rendered their judgment on it, and I think that it's their judgment and not our personal views on anything that really matters here.
UNIDENTIFIED FEMALE: Hey, guys...
UNIDENTIFIED FEMALE: We're OK. OK, guys.
UNIDENTIFIED FEMALE: What about the...
UNIDENTIFIED FEMALE: Does he want to touch -- do you want --
BLITZER: All right. So there we have the statement coming in from the U.S. attorney, the prosecutors in this case.
I want to immediately go to our national correspondent, Deborah Feyerick. She's there on the ground at the courthouse in Boston.
Deb, you were there. Walk us through what has happened for viewers here in the United States and around the world, who are just tuning in.
[17:10:08] DEBORAH FEYERICK, CNN CORRESPONDENT: Well, Wolf, we can tell you it took the jury about 14.5 hours over 3 days to reach their verdict. The verdict and the sentence, death on six of the 17 death-eligible counts.
They found him guilty, and they found that he deserved death for planting the bomb in front of the Forum restaurant, the bomb that killed 8-year-old Martin Richard, the youngest victim, as well as the exchange student, Lingzi Lu. They found that the crimes were heinous and depraved, and that for a those six capital counts, he should be put to death.
Now, Dzhokhar Tsarnaev stood during the reading of this verdict. It took almost 30 minutes for all of the counts to be read out loud. It took about 30 minutes, and there was this very heavy silence in the courtroom.
The judge had warned through his clerk that anyone who said anything during the reading would be held in contempt and would be treated accordingly. But everyone was silent. We saw some of the victims and their relatives dabbing tears from their eyes.
But Bill Richards, the father of that 8-year-old boy, he didn't show emotion. Neither did his wife. This has been such a tremendous strain on the entire family. They thought that the death penalty would not be the right thing, because they wanted Dzhokhar Tsarnaev locked away and forgotten in a place where no one would ever say his name.
It's unclear whether the defense will appeal. The defense, Wolf, did leave court. They were the first ones out of the court after meeting with Tsarnaev, immediately after he received the death sentence. They were the first ones out of that court. They went out the back door. They were asked for their reaction. They were asked whether they were going to appeal, and they simply said nothing. They walked away very somberly, and very soberly, deciding what their next move will be.
They really put all their emphasis on the mitigating factors, trying to soften Dzhokhar Tsarnaev, trying to say that it was his brother that was really responsible for this and that they wanted to portray him as a good kid, somebody who was well-liked by his teachers, by his aunts, by his uncles.
But most of the jurors found that, in fact, help was very well- liked and very well-respected by his teachers and even by his friends, but they found that, as for Tamerlan's role, that they disagreed. They didn't believe. At least three of the jurors didn't believe that he was really the ringleader, that he was the driver, instead deciding with -- deciding with the prosecution, who basically said they were co-conspirators. They were partners in crime. They were brothers in arms.
And it was a very powerful closing statement, closing argument, on Wednesday, when the prosecutor said, trying to sort of take the martyrdom aspect off the table, he said, "Death isn't giving Tsarnaev what he wants. Death is giving him what he deserves."
And the men and the women on that jury, they stood at attention, as did Dzhokhar Tsarnaev and his lawyers, as this was read. And Tsarnaev didn't show any emotion. He was sort of stoic, the way he's been the whole time. You know, I've seen it as almost being disengaged, disinterested. But at the end the judge thanked him for showing propriety during the entire proceedings. So a lot of people now voicing their opinion on whether it was the right sentence -- Wolf.
BLITZER: All right. Deb, stand by. I want to bring in our senior legal analyst, Jeffrey Toobin. He's a former federal prosecutor.
Jeffrey, the appeals process is going to go forward. He's been sentenced to death, but this will now presumably take years if, in fact, he is eventually executed?
JEFFREY TOOBIN, CNN SENIOR LEGAL ANALYST: That's certainly true. Timothy McVeigh was convicted of a similar act and not executed until 2001, four years later. And by modern death penalty standards, that was fast. I mean, we've had people in this country executed after 20 years on Death Row. So the legal process has miles and miles to go.
And there's one argument that actually may get some traction on appeal. Most appeals fail, and I think the likelihood this appeal will -- this will fail. But the one argument that might succeed is that this trial should not have taken place in Boston.
Now, that was even appealed before the trial, and there was a very closely argued appeal in the 1st Circuit Court of Appeals, 2-1 the judges said the trial could stay in Boston, but the argument that -- the community was so traumatized that this trial should have gone elsewhere is a powerful argument.
You know, the Oklahoma City bombing trial was moved to Denver, in part for just that reason. So I just think as the appeal process begins, and as you say, it will take years. That's the issue to keep an eye on. Whether this trial could fairly be held in Boston.
[17:15:06] BLITZER: All right. Jeffrey Toobin, I want you to stand by, as well. We're expecting to hear from some of the family members of those who were killed in this Boston Marathon bombing.
Let's remember who they are. Four individuals killed, all young. Martin Richard, 8 years old. Lingzi Lu, 23 years old. Krystle Campbell, 29 years old and the MIT security officer who was shot at point-blank range, Sean Collier. He was killed, as well.
We'll take a break. Much more of the breaking news right after this.
BLITZER: On the heels of a chilling audio message from its leader, ISIS launching a surprise offensive against a key Iraqi city only 70 miles from Baghdad. The terror group may be on the verge of recapturing Ramadi. It seized the police headquarters there; it raised its black flag over the provincial government building. Iraqi forces re fighting back with some more coalition airstrikes.
Let's go live to our Pentagon correspondent, Barbara Starr. Very disturbing information, Barbara. What are you learning?
BARBARA STARR, CNN PENTAGON CORRESPONDENT: Wolf, Ramadi is the second largest city in western Iraq. It is critical for the Iraqis to hold onto it. Right now a U.S. official tells me it may be down to 50/50 between ISIS and the Iraqi forces as to who controls the city. They've launched this offensive today from ISIS fighters, sending car bombs through the city breaches, trying to take back a building, raising their flag.
Officially, the Pentagon says it's an ebb and flow of the fight. Ramadi has been contested for months between the two sides, and the fighting goes back and forth.
But the reality is the U.S. conducting some 12 airstrikes in the last 72 hours there, trying to do everything they can to ensure the Iraqis are able to hold onto this city.
BLITZER: And the new audio from the ISIS leader, Abu Bakr al- Baghdadi, does that concern the Pentagon? What's their reaction over there?
STARR: You know, it's the same thread that we're hearing continuously. The Pentagon saying that audio proves that they're desperate, because he's asking for more recruits and more fighters.
The Pentagon very much insisting ISIS is on the defensive; they're no longer acting as an offensive military force, and all of these events reflect their attempt to hold onto territory.
Fair to say there's a lot of people that may disagree with the Pentagon's assessment, still see ISIS as a very potent force and the Iraqi forces struggling to hold onto what they have -- Wolf.
BLITZER: All right, Barbara, stand by. I want to get some more on what's going on.
Joining us, Democratic Congresswoman Tulsi Gabbard of Hawaii. She's a member of the Armed Services and Foreign Affairs Committee, also a veteran of service, military service in Iraq.
What's going on? ISIS was supposed to be kicked out of Ramadi, but now they're on the verge, it looks like, of taking over this key city in the Anbar Province? What's going on?
REP. TULSI GABBARD (D), HAWAII: I think, Wolf, what we're seeing here again is the issue I've brought up many times before. And that is that right now the United States policy and what's happening in Iraq is not addressing the core of the problem that's allowing ISIS to be able to continue to come back in particular into these Sunni stronghold areas. The fact that this central government in Baghdad is still not
arming and equipping the Kurds and the Sunnis, who are trying to fight for their homeland, fight for their territories and their people.
We saw in Tikrit, for example, ISIS was pushed out, but because there was no plan in place for the Sunni people to secure themselves, to provide this governance for their own area, we saw the Shia militia, the guys who were fighting against ISIS, going in and razing homes, and burglarizing, and stealing, and looting, and really terrorizing the people there.
So this is, again, another symptom of the problem that we're seeing where the United States is still not providing arms and weapons directly to the Sunni fighters and Kurdish fighters on the ground who are fighting against ISIS.
BLITZER: All right. I want you to stand by, Congresswoman. We have a lot more to discuss. It looks like the Iraqi military also right now, they're pretty depressing, missing in action once again.
Much more coming up. We'll take a quick break.
[17:28:03] BLITZER: We have more breaking news. A senior administration official now telling CNN, confirming that eight new coalition airstrikes against ISIS targets in Ramadi have taken place in the last five hours or so.
We're back with Democratic Congresswoman Tulsi Gabbard of Hawaii, an Iraq War veteran and member of the Armed Services and Foreign Affairs Committee.
Obviously, looks like they're desperate right now to prevent ISIS from taking over Ramadi. It was only a few weeks ago General Martin Dempsey, the outgoing chairman of the joint chiefs of staff, he said Ramadi was not symbolic in any way, not central to the future of Iraq. He made a much bigger deal about the Baiji oil refinery, which also seems to be in the control of ISIS, at least 80 percent of it right now. I don't get it.
GABBARD: Yes. Again, I think we're seeing a continued effect, or continued symptoms of some of the core problems that we've seen that have allowed this problem to occur in Iraq in the first place that has allowed ISIS to continue to maintain a stronghold and be able to come back to these strong Sunni, particularly the Sunni-held areas.
We just passed the defense bill today from the House, and we were able to include in there a provision that dealt directly with authorizing funding to the Sunni fighters and the Kurdish fighters, bypassing the central government in Baghdad, because we've seen their unwillingness to empower these fighters.
BLITZER: But they're not going to -- the administration says they've got to go through the central government. They say they have confidence in Haider al-Abadi, the new prime minister; they say he's better than Nuri al-Maliki, the old prime minister. And if you were to arm the Kurds directly or the moderates, Sunni forces in the Anbar province directly, that would undermine the strength, the sovereignty of that central Baghdad government.
GABBARD: Which again, this is an area where I disagree with the administration. We see a growing number of members of Congress who disagree with the administration on this point and will continue to push to get this funding and these weapons that these fighters who are -- who are really bravely fighting on the ground, that they really so desperately need to be effective.
One of the leaders, the major leader of the Sunni tribe fighters, a sheik who's coming here to Washington next week to plead their case, I'll meeting with him one on one as he really paints a realistic picture of what they're facing on the ground and what they need and how desperately they need it.
BLITZER: I know you've been critical of the Obama administration and you're a Democrat, because they refused to use the phrase "radical Islam," and you've been very critical.
Have they been in touch with you? Have they talked to you about that? I know you're critical of them for refusing to arm the Kurds, America's friends directly. What do they say to you?
GABBARD: Well, this is an area, unfortunately, where there's an agreement to disagree. We've heard arguments. They've heard my arguments. I've heard their argument and I think the issue here is that we have to stay focused on what our mission is.
Our mission is to defeat ISIS and these Islamic extremists who threaten not only people in the Middle East but we're seeing increasingly people around the world. So this continued failed policy of supporting one central government in Baghdad that is led by the Shia leadership that's heavily influenced by Iran, this does not best serve our core focus and mission which is and should be to defeat ISIS.
BLITZER: Congresswoman Tulsa Gabbard, thanks for coming in.
GABBARD: Thanks, Wolf. Aloha.
BLITZER: Coming up, other news we're following. The engineer whose train was going 160 miles an hour before it derailed finally talks to federal investigators. We're getting new information. Stand by.
[17:35:02] BLITZER: Robert Sumwalt, the lead investigators for the National Transportation Safety Board, updating us now. He just said that the engineer has been now interviewed by the NTSB and has been, in his words, extremely cooperative.
Let's listen in. ROBERT SUMWALT, NTSB BOARD MEMBER: And when asked, when asked he
demonstrated a very good knowledge of -- a very good working knowledge of the territory. Speed limitations, things like that. He began his railroad career while he was in college as a brakeman. He started with Amtrak in 2006 as a conductor. And in 2010 he game a locomotive engineer.
Since 2012 he has worked out of New York City and he's been on this particular job for several weeks. He works five days a week, it's an out and back trip to him. Goes to New York, Washington, and back to New York, five days a week. He said that he did not feel fatigued nor did he report any illness.
As we reported the other day, the train has three conductors. The conductor is -- is not able to be interviewed as he is still in the hospital. However, we did interview the two assistant conductors. I'll call it assistant conductor number one. She was -- she's 39 years old. She was hired by Amtrak in 2011. And she was in the fourth car which is the cafe car. She stated that before departing Washington the entire crew conducted a safety briefing, where they went over all of the speed restrictions along their intended route.
She reported it was a normal run through Philadelphia. Everything was normal, up through Philadelphia. And she said she essentially could hear the transmission of the locomotive engineers. The conductors carry radios and they are frequently talking to and listening to the locomotive engineer. So she could hear the transmissions from the locomotive engineer.
She reported that approximately three to four minutes after departing Philadelphia, she said she heard the engineer talking to SEPTA engineer. He recalled that the SEPTA engineer had reported to the train dispatcher that he had either been hit by a rock or shot at. And that the SEPTA engineer said that he had a broken windshield and he placed his train into emergency stop.
She also believed that she heard the engineer say something about -- she also believed that she heard her engineer say something about his train being struck by something. This is her recollection and certainly we are going to be conducting further investigation of this -- of this comment.
Our investigation has not independently confirmed this information, but we have seen damage to the left-hand lower portion of the Amtrak windshield that we have asked the FBI to come in and look at for us. We oftentimes rely on the FBI for their technical expertise in such areas. And they will be there tonight looking at this particular damage to the Amtrak locomotive. The windshield.
Of course, when the engine went through the -- went through the -- through the impact, the windshield was shattered, but there's particular damage there that we want them to look at for us.
We've secured the track image recorder, by the way, from the SEPTA train to see what we can learn from that. Now moving forward, right after she recalled hearing this conversation between the engineer and the -- her engineer and SEPTA engineer, she said that she felt rumbling and her train leaned over and her car went over on its side. She said they were not able to self-evacuate, and they waited for the emergency responders to get them out. She said she had about 15 passengers in her car.
[17:40:14] We asked what her relationship, working relationship was with her locomotive engineer. She said that she had worked with him a good bit and said that he was great to work with. She said he was always offering to help her with her job.
Now let's move to the assistant conductor number two. He's 35 years old. He was hired by Amtrak in May of last year. Just a few days before the accident. He had celebrated his one-year anniversary with Amtrak. He was in the seventh passenger car, that, of course, is the last passenger car, and he reported having about 40 people in his car. Up to the accident, he reported no problems, other than some radio problems, radio problems with his portable radio.
He said that sporadically he could hear but not sure that some of his transmissions were going out. At the point that we're describing at the location of the accident he said he felt shaking, then two major impacts. He said that interior seats disconnected, and he attempted to contact the Amtrak dispatch center, but does not recall receiving a response.
He assisted with the evacuation of injured passengers until instructed by emergency responders to go seek medical attention on his own. He said he had not worked much with the Amtrak engineer before the accident trip, but he did say that he was happy with the engineer and described the engineer as being very professional.
So what we've just described is the information that allowed us to delay the press conference so that we could report that information to you. We've got some other investigative activities that we'll fill you in on, on what's been going on. You know, we've mentioned through the week a 3-D laser scanner. We have done a 3-D laser scanning of the locomotive interior and exterior.
We've scanned an Exemplar passenger car so that we can compare the Exemplar passenger car to the damaged cars, and we've also documented interior safety features in all cars. We'll continue -- we've continued the testing of the signals and the signal circuitry. Basically as the tracks are being rebuilt, our signal specialists are going along to check the continuity of the signal circuitry. Over the weekend we plan to reassemble the train set as much as we can to put it back together, connect the brake lines, and conduct a brake test and that will take several days.
Over the course of the last few days, some of you have asked, what would we do if we could not talk to the engineer, and how would we resolve it, and one of the things we've called for in the wake of a fatal train crash in 2008 where 25 people were killed, including the engineer, the NTSB issued recommendations for forward-facing image recorders and inward-facing image recorders.
So something that would get a video image, video and audio image of what's going on inside the locomotive cab, as well as the outward- facing cameras, and, of course, this train did have an outward-facing camera. We also feel it's important to have the inward-facing cameras.
The FRA, that issue -- that recommendation was issued in 2010 when we completed our -- our investigation of that accident out in Chatsworth, California, and the FRA has replied that they do intend to act upon that recommendation. There's a lot to be done. I think over the last few days we've gotten a lot done. But this will be our final press briefing on-scene. Future information on this accident will be coming from our press office in Washington, D.C.
And in just a moment I'll ask Peter to explain that process, but basically I think you can follow us at our Web page, www.ntsb.gov, and also follow us at Twitter, I think you know our Twitter handle is @ntsb.
[17:45:10] I want to emphasize that even though this is the final press briefing, certainly there is a lot of work that needs to be done, and will be done over the next several days, while our investigative team is here in Philadelphia.
There's a lot that needs to be done and will be done, but, anyway, that's the end of my prepared remarks, and if you would, please raise your hand. I'll call on you and identify your outlet. Yes, ma'am?
UNIDENTIFIED FEMALE: (INAUDIBLE), "New York Post." You said that his route is from New York to Washington and then back to New York.
SUMWALT: Yes.
UNIDENTIFIED REPORTER: Was he coming back -- his second journey of the day?
SUMWALT: He does, it was at his second journey of the day? That was his, the answer is, it's one round trip. So he starts in the -- in the early afternoon. Washington -- excuse me. New York, Washington, back to New York. So it's one round trip.
UNIDENTIFIED REPORTER: And how much time is between that?
SUMWALT: How much time is between that? We will have his schedule. I don't have it immediately in front of me. I've often said, we are here to get information that will go away with the passage of time. His schedule we can do things like next week. We want to do train interviews and things like that through interviews. Yes, sir.
UNIDENTIFIED REPORTER: (INAUDIBLE). What else could that explain acceleration of the train?
SUMWALT: Other than human input, what else could explain the acceleration of the train? The train is -- the train does not have, I flew airplanes a long time. We had airplanes that had automatic throttles. The trains do not have automatic throttles.
It's a manual input. We're going to be through the -- through the event recorder, through the black box, if you will, we do one of the parameters recorded is throttle movement.
So we'll be looking at that to see if that might correspond with the -- with the speed increase. But we're also looking to see if there could be any type of mechanical anomaly that could potentially cause the train to accelerate without an input. So we'll come right here.
UNIDENTIFIED REPORTER: (INAUDIBLE). Have you been able to get any of his toxicology reports back, blood work, things like that, and are there any other video sources on the train that may show you what he was doing before the crash?
SUMWALT: Have we been able to get back the tox reports and is there any other video that we may be able to learn from. Let me address the video issue first. We're always surprised and happy that there are video sources that come from unintended sources like -- as has been reported on the media. There was a security camera that recorded some sparking or really an explosion, just the way it was described on TV, that probably came as a result of the catenary lines collapsing after the -- after the collision, after the accident.
So, you know, people have cell phone cameras and things like that. So we're always looking for additional sources of video information. If anybody has video information that we don't know about, we'd love to hear about it from our witness line, that witness line is witness@ntsb.gov. So we'd love to hear from that. Also --
BLITZER: All right. We're going to break away, we're going to continue to monitor this briefing. But Sarah Feinberg is here in THE SITUATION ROOM with me. She's the acting administrator of the Federal Railroad Administration. She's just back from Philadelphia herself.
Sarah, thanks very much for coming in. He's making news, Robert Sumwalt, the lead investigators for the NTSB, the National Transportation Safety Board. Tell us what we just heard.
SARAH FEINBERG, ACTING ADMINISTRATOR, FEDERAL RAILROAD ADMINISTRATION: Well, he's basically doing what the NTSB does better than anyone in the world, which is updating the public on the status of their investigation. So the NTSB is the lead investigator in this accident. The FRA also runs an investigation. We also partner with the NTSB, and you know, they update the public every day on the latest on their investigation. So that's exactly what you were hearing.
BLITZER: It was very encouraging to hear him describe the locomotive engineer as being extremely cooperative. Yes, he was -- he went to the interview with the NTSB with his lawyers, but that's understandable. That was encouraging. Wasn't it?
FEINBERG: Well, sure. I mean, you know, the first news out of an accident is frequently wrong and inaccurate information. We heard some earlier reports -- I think everyone was reporting that the engineer was not being cooperative. Mr. Sumwalt, Member Sumwalt, who was incredibly experienced, said yesterday that he wanted to put to rest the fact that the engineer wasn't being cooperative, but in fact he was being cooperative.
BLITZER: Now there was also an intriguing bit from one of the assistant conductors, who overheard a conversation between the engineer of this locomotive and another engineer from what he described as a SEPTA train, that's a Southeast Pennsylvania Transit Authority. That's a local commuter train.
FEINBERG: Yes.
[17:50:13] BLITZER: That some sort of projectile was thrown or hurled into the windshield there and may be into the windshield of this train, 188, the Amtrak train as well. You heard him say that.
FEINBERG: That's -- I did, and that's probably the perfect example of why the NTSB is so good at their work. You know, there's all kinds of assumptions going into an accident, it must have been caused by this or that or clearly here's the root cause of the accident, and that's new information right there, and that's why the NTSB is so good as their job.
BLITZER: Because we had heard that there was a -- minutes before this incident there was a separate incident involving this local commuter train where some sort of projectile was thrown or hurled at the windshield. But for the first time we're hearing now that the engineer of that train and the engineer of the Amtrak 188, they're saying, well, maybe something similar happened at 188. Have you heard anything along those lines?
FEINBERG: No, and I'll let the NTSB lead the investigation. That's their job. That's why they're so good. This is new information. They will get to the bottom of it. They are so good at getting to the root cause of the accident. That's new information to me but our investigators team with the NTSB and so I think they're getting that information as well.
BLITZER: And the engineer of Amtrak 188, he doesn't remember a lot, understandably so. He was in the lead car and all of a sudden it derailed. You can only imagine what he's been going through so maybe that's understandable as well. Where do we go from here?
FEINBERG: Well, the NTSB will continue their investigation, frequently takes another couple of days. Another couple of weeks. They'll probably a preliminary report of their findings. The FRA will do our investigation as well and over time will come to a conclusion and then we'll release that to the public so this tend to follow the same pattern every time.
BLITZER: What is the key question you need to know, the FRA, the Federal Railroad Administration, and you're the acting administrator?
FEINBERG: We need to know how this accident happened and how we can prevent it in the future. That's the most important thing is safety. It's our only mission and it's the most important thing that we do and so we'll be determining how this accident happened. How to stop it from happening in the future.
And in the meantime, is there anything that we can do to make sure that rail passengers are safe even before we have a determination of this accident. So, for example, you know, Amtrak in this area where the derailment happened has some technology on the southbound tracks that cap speed if the train is speeding. We've told them, we've instructed them before they reopen their tracks later next week they've got to put that same technology on the northbound side.
So if you've ever got a train speeding in that same area, that speed is going to be capped by technology. We've also told them they have to go take a new look at all of their curves, make sure that they've got technology in place where they need to and increase speed signage as well. And that's just the first thing we'll do. We'll probably take some additional steps, possibly even take some emergency orders -- execute some emergency orders later but those will be first steps.
BLITZER: So basically what I hear you saying is until Amtrak gets that automated equipment to make sure that if somebody -- if an engineer dozes off or is distracted by a cell phone or whatever, and is going too fast into a curve, there's going to be that technology, that system in place, that will automatically slow that train down. It's in certain areas, but it wasn't in this area where the train occurred. And you're not going to allow Amtrak to continue operations between Philadelphia and New York until they get that working?
FEINBERG: Well, there's a couple of different kinds of technology here. There's positive train control, which is the most detailed, the sharpest technology that's out there.
BLITZER: Which exists, but was not existing in Philadelphia in this area?
FEINBERG: Exactly. And Amtrak has said that they will implement that technology by the end of the year. It's incredibly expensive, very complicated, requires a lot of testing. That's going to take --
BLITZER: Is that good enough for you?
FEINBERG: PTC is great. PTC --
BLITZER: But I mean, by the end of the year?
FEINBERG: That's when the deadline is, the congressionally mandated deadline.
BLITZER: But you're going to live with that?
FEINBERG: We want -- we want to implement to it as soon as possible --
BLITZER: So what do you want them to do specifically by next week in order to allow the resumption of service between Philadelphia and New York?
FEINBERG: We want them to match on the northbound side the technology they already have on the southbound side, which is less than PTC, but it still caps the speed of the train. So if the train is speeding, it sends a message to the -- to the engineer saying you're speeding. The engineer has to react to that or slow the train down. If he or she doesn't, it automatically slows the train down.
BLITZER: What does Amtrak say? Can they do it by next week?
FEINBERG: They've said they'll do it.
BLITZER: They can do it. So -- what day do you think the service between Philadelphia and New York will be resumed?
FEINBERG: Amtrak has said that they wanted to resume service on Monday or Tuesday. Be it full capacity. They have to get this done first.
BLITZER: Is it safe for Americans to get on these Amtrak trains right now?
FEINBERG: Absolutely. Absolutely. 300 million Americans travel on the north border --
BLITZER: Because there have been 10 derailments on Amtrak this year alone.
FEINBERG: Well, I'll push you on that a little bit. Most of those derailments happened in rail yard. That doesn't mean it's OK for them to happen, but frequently we're talking about derailments in rail yards amount to some trains bumping into each other, they're very slow speeds. No injuries.
The reality is that the first derailment on the Northeast Corridor in many, many years. Rail travel is incredibly safe. That doesn't mean that we'll ever stop doing everything we can to keep passengers safe.
[17:55:08] BLITZER: Sarah Feinberg, thanks very much for coming in. Good luck.
FEINBERG: Thanks for having me. Thank you.
BLITZER: We're counting on you.
FEINBERG: Thanks for having me.
BLITZER: Sarah Feinberg is the acting administrator of the Federal Railroad Administration.
FEINBERG: Thanks.
BLITZER: Coming up, ISIS on the offensive, a surprise attack puts the terror group on the verge of recapturing a key Iraqi city, only 70 miles from Baghdad. All the late developments when we come back.
BLITZER: Happening now, breaking news. Death sentence, the jury hands down the ultimate punishment for the Boston marathon bomber, convicted terrorist Dzokhar Tsarnaev. We're learning new details of his reaction inside the courtroom.


text:
Q: How to detach and restore jQuery Mobile pages I am working on a jQuery Mobile app that has a known set of distinct thematic pages, e.g.:
<div id="theme1_page" data-role="page" class="ui-page" data-theme="c">

The pages have values I populate via a spatial query. I'd like the user to be able to choose which of the pages they see and restore or change their preference of visible pages at any time.
On a Settings panel I want to use a series of check boxes, e.g.:
$('input[id^="checkbox_"]').on( "change", function ()

To turn off a page via detach() rather than hide() or remove() (which cause other problems) and turn the page back on later or even in another session.
I want to store the state (on/off) and order of all pages for use at another time.
As I'm quite new to this, would placing the page into localStorage somehow be the means to keep track of things and then be the means to retrieve the page on demand to insert at the proper index?
How does one store each detached page's values, events, position in the array of pages, and visible state?

A: It is possible to store it in a variable/namespace if you do not need to have it saved across sessions.
If you do need it saved across sessions, the. you'll definitely need localstorage or some way of keeping track of it server side either through the DB or the session object might be a good idea.
Localstorage is pretty much like namespacing , learn a bit more about it here : http://www.w3schools.com/html/html5_webstorage.asp

redpajama_set_name: RedPajamaStackExchange


laying ceramic floor tiles porcelain tile ceramic patterns for bathroom floors floor tiles fitting laying design good how to a laying ceramic floor tiles on chipboard.
bistro style table cafe style table and chairs bistro chair bar kitchen cafe style table and chairs bistro chair bar kitchen cosco 3 piece folding bistro style patio table and chairs set.
8 light 8 light kitchen island pendant 8 light vanity fixture.
garden tractor snow plow mf garden tractor w snow plow garden tractor snow plow wings.
fort worth custom pool pool houses the next level custom pool covers fort worth tx.
weaver glass one pint embossed lettering weaver quality blue ribbon glass milk bottle resource weaver glassdoor.
table spoons six antique silver old thread military pattern table spoons for sale tablespoons in a cup converter.
pink and grey bedroom ideas grey and white bedroom pink and grey bedroom best pink grey bedrooms ideas on grey bedrooms grey and white bedroom gray and pink master bedroom ideas.
joss and main upholstered bed and main beds upholstered canopy bed and main bedding joss and main king upholstered bed.
mission style bedroom set bedroom set craftsman style dining room chairs bed and furniture sets black wood bedroom furniture broyhill mission style bedroom furniture.


Kirk O. Hanson signs off as executive director for the Markkula Center for Applied Ethics.
Kirk O. Hanson has been called "the conscience of Silicon Valley" for good reason: He's spent most of his life burrowing into the thorny field of business and professional ethics, studying and teaching about real-life applications and consequences. At the center, he led 25 staff members and 70 affiliated faculty scholars who are sought-after experts in all areas of ethics—from medicine to the internet and beyond.
With the refrain, "Be compassionate and empathetic. Be full of purpose," Hanson marked his last graduation as executive director for the Markkula Center for Applied Ethics. For nearly half the center's existence, he shepherded it to national prominence. Hanson used the 2018 commencement to encourage ethical decision-making—even when it isn't easy.
Read Hanson's answers to our questions in this Q&A.


The sun came out on Saturday. It's not that we haven't seen it for months but this was the first time for months that you could say it was warm, or at least warmish. Running around at uni-hockey training I wasn't the only one to end up in a t-shirt. Since the start of January, after training on Saturdays, Novi Most has been running a social session for a couple of hours. Most of the team will turn up joined by a number of other young people from the area.
So far this year the sessions have happened inside – apart from one snowy weekend that saw some impromptu 'ice hockey' happen in the area behind the building. This week the sunshine and warm weather prompted our co-worker to suddenly decide to get all the lads clearing leaves and generally tidying up the yard outside. He is unashamedly keen to have this space ready for the onset of barbecue season! And so an industrious half hour from the boys saw a splendid piece of early spring cleaning accomplished under the watchful gaze of the girls. Was it sexist not to hand one of them a broom? Not in this country. It's been our observation that gender roles here have well established and accepted norms. Many people seem to have a clear distinction between what is men's work and women's work, and I certainly didn't catch anybody complaining about that in this instance!


text:
#include "ircconnection.h"
#include "ircconnection_p.h"
#include "ircnetwork_p.h"
#include "irccommand_p.h"
#include "ircprotocol.h"
#include "ircnetwork.h"
#include "irccommand.h"
#include "ircmessage.h"
#include "ircdebug_p.h"
#include "ircfilter.h"
#include "irccore_p.h"
#include "irc.h"
#include <QLocale>
#include <QRegExp>
#include <QDateTime>
#include <QTcpSocket>
#include <QTextCodec>
#include <QMetaObject>
#include <QMetaMethod>
#include <QMetaEnum>
#ifndef QT_NO_SSL
#include <QSslSocket>
#include <QSslError>
#endif // QT_NO_SSL
#include <QDataStream>
#include <QVariantMap>

IRC_BEGIN_NAMESPACE

/*!
    \file ircconnection.h
    \brief \#include <IrcConnection>
 */

/*!
    \class IrcConnection ircconnection.h IrcConnection
    \ingroup core
    \brief Provides means to establish a connection to an IRC server.

    \section connection-management Connection management

    Before \ref open() "opening" a connection, it must be first initialized
    with \ref host, \ref userName, \ref nickName and \ref realName.

    The connection status may be queried at any time via status(). Also
    \ref active "isActive()" and \ref connected "isConnected()" are provided
    for convenience. In addition to the \ref status "statusChanged()" signal,
    the most important statuses are informed via the following convenience
    signals:
    \li connecting() -
        The connection is being established.
    \li \ref connected "connected()" -
        The IRC connection has been established, and the server is ready to receive commands.
    \li disconnected() -
        The connection has been lost.

    \section receiving-messages Receiving messages

    Whenever a message is received from the server, the messageReceived()
    signal is emitted. Also message type specific signals are provided
    for convenience. See messageReceived() and IrcMessage and its
    subclasses for more details.

    \section sending-commands Sending commands

    Sending commands to a server is most conveniently done by creating
    them via the various static \ref IrcCommand "IrcCommand::createXxx()"
    methods and passing them to sendCommand(). Also sendData() is provided
    for more low-level access. See IrcCommand for more details.

    \section example Example

    \code
    IrcConnection* connection = new IrcConnection(this);
    connect(connection, SIGNAL(messageReceived(IrcMessage*)), this, SLOT(onMessageReceived(IrcMessage*)));
    connection->setHost("irc.server.com");
    connection->setUserName("me");
    connection->setNickName("myself");
    connection->setRealName("And I");
    connection->sendCommand(IrcCommand::createJoin("#mine"));
    connection->open();
    \endcode

    \sa IrcNetwork, IrcMessage, IrcCommand
 */

/*!
    \enum IrcConnection::Status
    This enum describes the connection status.
 */

/*!
    \var IrcConnection::Inactive
    \brief The connection is inactive.
 */

/*!
    \var IrcConnection::Waiting
    \brief The connection is waiting for a reconnect.
 */

/*!
    \var IrcConnection::Connecting
    \brief The connection is being established.
 */

/*!
    \var IrcConnection::Connected
    \brief The connection has been established.
 */

/*!
    \var IrcConnection::Closing
    \brief The connection is being closed.
 */

/*!
    \var IrcConnection::Closed
    \brief The connection has been closed.
 */

/*!
    \var IrcConnection::Error
    \brief The connection has encountered an error.
 */

/*!
    \fn void IrcConnection::connecting()

    This signal is emitted when the connection is being established.

    The underlying \ref socket has connected, but the IRC handshake is
    not yet finished and the server is not yet ready to receive commands.
 */

/*!
    \fn void IrcConnection::nickNameRequired(const QString& reserved, QString* alternate)

    This signal is emitted when the requested nick name is \a reserved
    and an \a alternate nick name should be provided.

    An alternate nick name may be set via the provided argument, by changing
    the \ref nickName property, or by sending a nick command directly.

    \sa nickNames, IrcCommand::createNick(), Irc::ERR_NICKNAMEINUSE, Irc::ERR_NICKCOLLISION
 */

/*!
    \fn void IrcConnection::channelKeyRequired(const QString& channel, QString* key)

    This signal is emitted when joining a \a channel requires a \a key.
    The key may be set via the provided argument, or by sending a new
    join command directly.

    \sa IrcCommand::createJoin(), Irc::ERR_BADCHANNELKEY
 */

/*!
    \fn void IrcConnection::disconnected()

    This signal is emitted when the connection has been lost.
 */

/*!
    \fn void IrcConnection::socketError(QAbstractSocket::SocketError error)

    This signal is emitted when a \ref socket \a error occurs.

    \sa QAbstractSocket::error()
 */

/*!
    \fn void IrcConnection::socketStateChanged(QAbstractSocket::SocketState state)

    This signal is emitted when the \a state of the underlying \ref socket changes.

    \sa QAbstractSocket::stateChanged()
 */

/*!
    \since 3.2
    \fn void IrcConnection::secureError()

    This signal is emitted when SSL socket error occurs.

    Either QSslSocket::sslErrors() was emitted, or the handshake failed
    meaning that the server is not SSL-enabled.
 */

/*!
    \fn void IrcConnection::messageReceived(IrcMessage* message)

    This signal is emitted when a \a message is received.

    In addition, message type specific signals are provided for convenience:
    \li void accountMessageReceived(\ref IrcAccountMessage* message) (\b since 3.3)
    \li void awayMessageReceived(\ref IrcAwayMessage* message) (\b since 3.3)
    \li void batchMessageReceived(\ref IrcBatchMessage* message) (\b since 3.5)
    \li void capabilityMessageReceived(\ref IrcCapabilityMessage* message)
    \li void errorMessageReceived(\ref IrcErrorMessage* message)
    \li void hostChangeMessageReceived(\ref IrcHostChangeMessage* message) (\b since 3.4)
    \li void inviteMessageReceived(\ref IrcInviteMessage* message)
    \li void joinMessageReceived(\ref IrcJoinMessage* message)
    \li void kickMessageReceived(\ref IrcKickMessage* message)
    \li void modeMessageReceived(\ref IrcModeMessage* message)
    \li void motdMessageReceived(\ref IrcMotdMessage* message)
    \li void namesMessageReceived(\ref IrcNamesMessage* message)
    \li void nickMessageReceived(\ref IrcNickMessage* message)
    \li void noticeMessageReceived(\ref IrcNoticeMessage* message)
    \li void numericMessageReceived(\ref IrcNumericMessage* message)
    \li void partMessageReceived(\ref IrcPartMessage* message)
    \li void pingMessageReceived(\ref IrcPingMessage* message)
    \li void pongMessageReceived(\ref IrcPongMessage* message)
    \li void privateMessageReceived(\ref IrcPrivateMessage* message)
    \li void quitMessageReceived(\ref IrcQuitMessage* message)
    \li void topicMessageReceived(\ref IrcTopicMessage* message)
    \li void whoisMessageReceived(\ref IrcWhoisMessage* message) (\b since 3.3)
    \li void whowasMessageReceived(\ref IrcWhowasMessage* message) (\b since 3.3)
    \li void whoReplyMessageReceived(\ref IrcWhoReplyMessage* message) (\b since 3.1)
 */

#ifndef IRC_DOXYGEN
IrcConnectionPrivate::IrcConnectionPrivate() :
    encoding("ISO-8859-15"),
    host(),
    userName(),
    nickName(),
    realName()
{
}

void IrcConnectionPrivate::init(IrcConnection* connection)
{
    q_ptr = connection;
    network = IrcNetworkPrivate::create(connection);
    connection->setSocket(new QTcpSocket(connection));
    connection->setProtocol(new IrcProtocol(connection));
    QObject::connect(&reconnecter, SIGNAL(timeout()), connection, SLOT(_irc_reconnect()));
}

void IrcConnectionPrivate::_irc_connected()
{
    Q_Q(IrcConnection);
    closed = false;
    pendingOpen = false;
    emit q->connecting();
    if (q->isSecure())
        QMetaObject::invokeMethod(socket, "startClientEncryption");
    protocol->open();
}

void IrcConnectionPrivate::_irc_disconnected()
{
    Q_Q(IrcConnection);
    protocol->close();
    emit q->disconnected();
    reconnect();
}

void IrcConnectionPrivate::_irc_error(QAbstractSocket::SocketError error)
{
    Q_Q(IrcConnection);
    if (error == QAbstractSocket::SslHandshakeFailedError) {
        ircDebug(q, IrcDebug::Error) << error;
        setStatus(IrcConnection::Error);
        emit q->secureError();
    } else if (!closed || (error != QAbstractSocket::RemoteHostClosedError && error != QAbstractSocket::UnknownSocketError)) {
        ircDebug(q, IrcDebug::Error) << error;
        emit q->socketError(error);
        setStatus(IrcConnection::Error);
        reconnect();
    }
}

void IrcConnectionPrivate::_irc_sslErrors()
{
    Q_Q(IrcConnection);
    QStringList errors;
#ifndef QT_NO_SSL
    QSslSocket* ssl = qobject_cast<QSslSocket*>(socket);
    if (ssl) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
        foreach (const QSslError& error, ssl->sslHandshakeErrors())
#else
        foreach (const QSslError& error, ssl->sslErrors())
#endif
            errors += error.errorString();
    }
#endif
    ircDebug(q, IrcDebug::Error) << errors;
    emit q->secureError();
}

void IrcConnectionPrivate::_irc_state(QAbstractSocket::SocketState state)
{
    Q_Q(IrcConnection);
    switch (state) {
    case QAbstractSocket::UnconnectedState:
        if (closed)
            setStatus(IrcConnection::Closed);
        break;
    case QAbstractSocket::ClosingState:
        if (status != IrcConnection::Error && status != IrcConnection::Waiting)
            setStatus(IrcConnection::Closing);
        break;
    case QAbstractSocket::HostLookupState:
    case QAbstractSocket::ConnectingState:
    case QAbstractSocket::ConnectedState:
    default:
        setStatus(IrcConnection::Connecting);
        break;
    }
    emit q->socketStateChanged(state);
}

void IrcConnectionPrivate::_irc_reconnect()
{
    Q_Q(IrcConnection);
    if (!q->isActive()) {
        reconnecter.stop();
        q->open();
    }
}

void IrcConnectionPrivate::_irc_readData()
{
    protocol->read();
}

void IrcConnectionPrivate::_irc_filterDestroyed(QObject* filter)
{
    messageFilters.removeAll(filter);
    commandFilters.removeAll(filter);
}

static bool parseServer(const QString& server, QString* host, int* port, bool* ssl)
{
    QStringList p = server.split(QRegExp("[: ]"), Qt::SkipEmptyParts);
    *host = p.value(0);
    *ssl = p.value(1).startsWith(QLatin1Char('+'));
    bool ok = false;
    *port = p.value(1).toInt(&ok);
    if (*port == 0)
        *port = 6667;
    return !host->isEmpty() && (p.value(1).isEmpty() || ok) && (p.count() == 1 || p.count() == 2);
}

void IrcConnectionPrivate::open()
{
    Q_Q(IrcConnection);
    if (q->isActive()) {
        pendingOpen = true;
    } else {
        closed = false;
        if (!servers.isEmpty()) {
            QString h; int p; bool s;
            QString server = servers.value((++currentServer) % servers.count());
            if (!parseServer(server, &h, &p, &s))
                qWarning() << "IrcConnection::servers: malformed line" << server;
            q->setHost(h);
            q->setPort(p);
            q->setSecure(s);
        }
        socket->connectToHost(host, port);
        setConnectionCount(connectionCount + 1);
    }
}

void IrcConnectionPrivate::reconnect()
{
    if (enabled && (status != IrcConnection::Closed || !closed || pendingOpen) && !reconnecter.isActive() && reconnecter.interval() > 0) {
        pendingOpen = false;
        reconnecter.start();
        setStatus(IrcConnection::Waiting);
    }
}

void IrcConnectionPrivate::setConnectionCount(int count)
{
    Q_Q(IrcConnection);
    if (connectionCount != count) {
        connectionCount = count;
        emit q->connectionCountChanged(count);
    }
}

void IrcConnectionPrivate::setNick(const QString& nick)
{
    Q_Q(IrcConnection);
    if (nickName != nick) {
        nickName = nick;
        emit q->nickNameChanged(nick);
    }
}

void IrcConnectionPrivate::setStatus(IrcConnection::Status value)
{
    Q_Q(IrcConnection);
    if (status != value) {
        const bool wasConnected = q->isConnected();
        status = value;
        emit q->statusChanged(value);

        if (!wasConnected && q->isConnected()) {
            emit q->connected();
            foreach (const QByteArray& data, pendingData)
                q->sendRaw(data);
            pendingData.clear();
        }
        ircDebug(q, IrcDebug::Status) << status << qPrintable(host) << port;
    }
}

void IrcConnectionPrivate::setInfo(const QHash<QString, QString>& info)
{
    Q_Q(IrcConnection);
    const QString oldName = q->displayName();
    IrcNetworkPrivate* priv = IrcNetworkPrivate::get(network);
    priv->setInfo(info);
    const QString newName = q->displayName();
    if (oldName != newName)
        emit q->displayNameChanged(newName);
}

bool IrcConnectionPrivate::receiveMessage(IrcMessage* msg)
{
    Q_Q(IrcConnection);
    if (msg->type() == IrcMessage::Join && msg->isOwn()) {
        replies.clear();
    } else if (msg->type() == IrcMessage::Numeric) {
        int code = static_cast<IrcNumericMessage*>(msg)->code();
        if (code == Irc::RPL_NAMREPLY || code == Irc::RPL_ENDOFNAMES) {
            if (!replies.contains(Irc::RPL_ENDOFNAMES))
                msg->setFlag(IrcMessage::Implicit);
        } else if (code == Irc::RPL_TOPIC || code == Irc::RPL_NOTOPIC || code == Irc::RPL_TOPICWHOTIME || code == Irc::RPL_CHANNEL_URL || code == Irc::RPL_CREATIONTIME) {
            if (!replies.contains(code))
                msg->setFlag(IrcMessage::Implicit);
        }
        replies.insert(code);
    }

    bool filtered = false;
    for (int i = messageFilters.count() - 1; !filtered && i >= 0; --i) {
        IrcMessageFilter* filter = qobject_cast<IrcMessageFilter*>(messageFilters.at(i));
        if (filter)
            filtered |= filter->messageFilter(msg);
    }

    if (!filtered) {
        emit q->messageReceived(msg);

        switch (msg->type()) {
        case IrcMessage::Account:
            emit q->accountMessageReceived(static_cast<IrcAccountMessage*>(msg));
            break;
        case IrcMessage::Away:
            emit q->awayMessageReceived(static_cast<IrcAwayMessage*>(msg));
            break;
        case IrcMessage::Batch:
            emit q->batchMessageReceived(static_cast<IrcBatchMessage*>(msg));
            break;
        case IrcMessage::Capability:
            emit q->capabilityMessageReceived(static_cast<IrcCapabilityMessage*>(msg));
            break;
        case IrcMessage::Error:
            emit q->errorMessageReceived(static_cast<IrcErrorMessage*>(msg));
            break;
        case IrcMessage::HostChange:
            emit q->hostChangeMessageReceived(static_cast<IrcHostChangeMessage*>(msg));
            break;
        case IrcMessage::Invite:
            emit q->inviteMessageReceived(static_cast<IrcInviteMessage*>(msg));
            break;
        case IrcMessage::Join:
            emit q->joinMessageReceived(static_cast<IrcJoinMessage*>(msg));
            break;
        case IrcMessage::Kick:
            emit q->kickMessageReceived(static_cast<IrcKickMessage*>(msg));
            break;
        case IrcMessage::Mode:
            emit q->modeMessageReceived(static_cast<IrcModeMessage*>(msg));
            break;
        case IrcMessage::Motd:
            emit q->motdMessageReceived(static_cast<IrcMotdMessage*>(msg));
            break;
        case IrcMessage::Names:
            emit q->namesMessageReceived(static_cast<IrcNamesMessage*>(msg));
            break;
        case IrcMessage::Nick:
            emit q->nickMessageReceived(static_cast<IrcNickMessage*>(msg));
            break;
        case IrcMessage::Notice:
            emit q->noticeMessageReceived(static_cast<IrcNoticeMessage*>(msg));
            break;
        case IrcMessage::Numeric:
            emit q->numericMessageReceived(static_cast<IrcNumericMessage*>(msg));
            break;
        case IrcMessage::Part:
            emit q->partMessageReceived(static_cast<IrcPartMessage*>(msg));
            break;
        case IrcMessage::Ping:
            emit q->pingMessageReceived(static_cast<IrcPingMessage*>(msg));
            break;
        case IrcMessage::Pong:
            emit q->pongMessageReceived(static_cast<IrcPongMessage*>(msg));
            break;
        case IrcMessage::Private:
            emit q->privateMessageReceived(static_cast<IrcPrivateMessage*>(msg));
            break;
        case IrcMessage::Quit:
            emit q->quitMessageReceived(static_cast<IrcQuitMessage*>(msg));
            break;
        case IrcMessage::Topic:
            emit q->topicMessageReceived(static_cast<IrcTopicMessage*>(msg));
            break;
        case IrcMessage::Whois:
            emit q->whoisMessageReceived(static_cast<IrcWhoisMessage*>(msg));
            break;
        case IrcMessage::Whowas:
            emit q->whowasMessageReceived(static_cast<IrcWhowasMessage*>(msg));
            break;
        case IrcMessage::WhoReply:
            emit q->whoReplyMessageReceived(static_cast<IrcWhoReplyMessage*>(msg));
            break;
        case IrcMessage::Unknown:
        default:
            break;
        }
    }

    if (!msg->parent() || msg->parent() == q)
        msg->deleteLater();

    return !filtered;
}

IrcCommand* IrcConnectionPrivate::createCtcpReply(IrcPrivateMessage* request)
{
    Q_Q(IrcConnection);
    IrcCommand* reply = nullptr;
    const QMetaObject* metaObject = q->metaObject();
    int idx = metaObject->indexOfMethod("createCtcpReply(QVariant)");
    if (idx != -1) {
        // QML: QVariant createCtcpReply(QVariant)
        QVariant ret;
        QMetaMethod method = metaObject->method(idx);
        method.invoke(q, Q_RETURN_ARG(QVariant, ret), Q_ARG(QVariant, QVariant::fromValue(request)));
        reply = ret.value<IrcCommand*>();
    } else {
        // C++: IrcCommand* createCtcpReply(IrcPrivateMessage*)
        idx = metaObject->indexOfMethod("createCtcpReply(IrcPrivateMessage*)");
        QMetaMethod method = metaObject->method(idx);
        method.invoke(q, Q_RETURN_ARG(IrcCommand*, reply), Q_ARG(IrcPrivateMessage*, request));
    }
    return reply;
}
#endif // IRC_DOXYGEN

/*!
    Constructs a new IRC connection with \a parent.
 */
IrcConnection::IrcConnection(QObject* parent) : QObject(parent), d_ptr(new IrcConnectionPrivate)
{
    Q_D(IrcConnection);
    d->init(this);
}

/*!
    Constructs a new IRC connection with \a host and \a parent.
 */
IrcConnection::IrcConnection(const QString& host, QObject* parent) : QObject(parent), d_ptr(new IrcConnectionPrivate)
{
    Q_D(IrcConnection);
    d->init(this);
    setHost(host);
}

/*!
    Destructs the IRC connection.
 */
IrcConnection::~IrcConnection()
{
    close();
    emit destroyed(this);
}

/*!
    \since 3.4

    Clones the IRC connection.
 */
IrcConnection* IrcConnection::clone(QObject *parent) const
{
    IrcConnection* connection = new IrcConnection(parent);
    connection->setHost(host());
    connection->setPort(port());
    connection->setServers(servers());
    connection->setUserName(userName());
    connection->setNickName(nickName());
    connection->setRealName(realName());
    connection->setPassword(password());
    connection->setNickNames(nickNames());
    connection->setDisplayName(displayName());
    connection->setUserData(userData());
    connection->setEncoding(encoding());
    connection->setEnabled(isEnabled());
    connection->setReconnectDelay(reconnectDelay());
    connection->setSecure(isSecure());
    connection->setSaslMechanism(saslMechanism());
    return connection;
}

/*!
    This property holds the FALLBACK encoding for received messages.

    The fallback encoding is used when the message is detected not
    to be valid \c UTF-8 and the consequent auto-detection of message
    encoding fails. See QTextCodec::availableCodecs() for the list of
    supported encodings.

    The default value is \c ISO-8859-15.

    \par Access functions:
    \li QByteArray encoding() const
    \li void setEncoding(const QByteArray& encoding)

    \sa QTextCodec::availableCodecs(), QTextCodec::codecForLocale()
 */
QByteArray IrcConnection::encoding() const
{
    Q_D(const IrcConnection);
    return d->encoding;
}

void IrcConnection::setEncoding(const QByteArray& encoding)
{
    Q_D(IrcConnection);
    extern bool irc_is_supported_encoding(const QByteArray& encoding); // ircmessagedecoder.cpp
    if (!irc_is_supported_encoding(encoding)) {
        qWarning() << "IrcConnection::setEncoding(): unsupported encoding" << encoding;
        return;
    }
    d->encoding = encoding;
}

/*!
    This property holds the server host.

    \par Access functions:
    \li QString host() const
    \li void setHost(const QString& host)

    \par Notifier signal:
    \li void hostChanged(const QString& host)
 */
QString IrcConnection::host() const
{
    Q_D(const IrcConnection);
    return d->host;
}

void IrcConnection::setHost(const QString& host)
{
    Q_D(IrcConnection);
    if (d->host != host) {
        if (isActive())
            qWarning("IrcConnection::setHost() has no effect until re-connect");
        const QString oldName = displayName();
        d->host = host;
        emit hostChanged(host);
        const QString newName = displayName();
        if (oldName != newName)
            emit displayNameChanged(newName);
    }
}

/*!
    This property holds the server port.

    The default value is \c 6667.

    \par Access functions:
    \li int port() const
    \li void setPort(int port)

    \par Notifier signal:
    \li void portChanged(int port)
 */
int IrcConnection::port() const
{
    Q_D(const IrcConnection);
    return d->port;
}

void IrcConnection::setPort(int port)
{
    Q_D(IrcConnection);
    if (d->port != port) {
        if (isActive())
            qWarning("IrcConnection::setPort() has no effect until re-connect");
        d->port = port;
        emit portChanged(port);
    }
}

/*!
    \since 3.3

    This property holds the list of servers.

    The list of servers is automatically cycled through when reconnecting.

    \par Access functions:
    \li QStringList servers() const
    \li void setServers(const QStringList& servers)

    \par Notifier signal:
    \li void serversChanged(const QStringList& servers)

    \sa isValidServer()
 */
QStringList IrcConnection::servers() const
{
    Q_D(const IrcConnection);
    return d->servers;
}

void IrcConnection::setServers(const QStringList& servers)
{
    Q_D(IrcConnection);
    if (d->servers != servers) {
        d->servers = servers;
        emit serversChanged(servers);
    }
}

/*!
    \since 3.3

    Returns \c true if the server line syntax is valid.

    The syntax is:
    \code
    host <[+]port>
    \endcode
    where port is optional (defaults to \c 6667) and \c + prefix denotes SSL.

    \sa servers
 */
bool IrcConnection::isValidServer(const QString& server)
{
    QString h; int p; bool s;
    return parseServer(server, &h, &p, &s);
}

/*!
    This property holds the user name.

    \note Changing the user name has no effect until the connection is re-established.

    \par Access functions:
    \li QString userName() const
    \li void setUserName(const QString& name)

    \par Notifier signal:
    \li void userNameChanged(const QString& name)
 */
QString IrcConnection::userName() const
{
    Q_D(const IrcConnection);
    return d->userName;
}

void IrcConnection::setUserName(const QString& name)
{
    Q_D(IrcConnection);
    QString user = name.split(" ", Qt::SkipEmptyParts).value(0).trimmed();
    if (d->userName != user) {
        if (isActive())
            qWarning("IrcConnection::setUserName() has no effect until re-connect");
        d->userName = user;
        emit userNameChanged(user);
    }
}

/*!
    This property holds the current nick name.

    \par Access functions:
    \li QString nickName() const
    \li void setNickName(const QString& name)

    \par Notifier signal:
    \li void nickNameChanged(const QString& name)

    \sa nickNames
 */
QString IrcConnection::nickName() const
{
    Q_D(const IrcConnection);
    return d->nickName;
}

void IrcConnection::setNickName(const QString& name)
{
    Q_D(IrcConnection);
    QString nick = name.split(" ", Qt::SkipEmptyParts).value(0).trimmed();
    if (d->nickName != nick) {
        if (isActive())
            sendCommand(IrcCommand::createNick(nick));
        else
            d->setNick(nick);
    }
}

/*!
    This property holds the real name.

    \note Changing the real name has no effect until the connection is re-established.

    \par Access functions:
    \li QString realName() const
    \li void setRealName(const QString& name)

    \par Notifier signal:
    \li void realNameChanged(const QString& name)
 */
QString IrcConnection::realName() const
{
    Q_D(const IrcConnection);
    return d->realName;
}

void IrcConnection::setRealName(const QString& name)
{
    Q_D(IrcConnection);
    if (d->realName != name) {
        if (isActive())
            qWarning("IrcConnection::setRealName() has no effect until re-connect");
        d->realName = name;
        emit realNameChanged(name);
    }
}

/*!
    This property holds the password.

    \par Access functions:
    \li QString password() const
    \li void setPassword(const QString& password)

    \par Notifier signal:
    \li void passwordChanged(const QString& password)
 */
QString IrcConnection::password() const
{
    Q_D(const IrcConnection);
    return d->password;
}

void IrcConnection::setPassword(const QString& password)
{
    Q_D(IrcConnection);
    if (d->password != password) {
        if (isActive())
            qWarning("IrcConnection::setPassword() has no effect until re-connect");
        d->password = password;
        emit passwordChanged(password);
    }
}

/*!
    \since 3.3

    This property holds the nick names.

    The list of nick names is automatically cycled through when the
    current nick name is reserved. If all provided nick names are
    reserved, the nickNameRequired() signal is emitted.

    \par Access functions:
    \li QStringList nickNames() const
    \li void setNickNames(const QStringList& names)

    \par Notifier signal:
    \li void nickNamesChanged(const QStringList& names)

    \sa nickName, nickNameRequired()
 */
QStringList IrcConnection::nickNames() const
{
    Q_D(const IrcConnection);
    return d->nickNames;
}

void IrcConnection::setNickNames(const QStringList& names)
{
    Q_D(IrcConnection);
    if (d->nickNames != names) {
        d->nickNames = names;
        emit nickNamesChanged(names);
    }
}

/*!
    This property holds the display name.

    Unless explicitly set, display name resolves to IrcNetwork::name
    or IrcConnection::host while the former is not known.

    \par Access functions:
    \li QString displayName() const
    \li void setDisplayName(const QString& name)

    \par Notifier signal:
    \li void displayNameChanged(const QString& name)
 */
QString IrcConnection::displayName() const
{
    Q_D(const IrcConnection);
    QString name = d->displayName;
    if (name.isEmpty())
        name = d->network->name();
    if (name.isEmpty())
        name = d->host;
    return name;
}

void IrcConnection::setDisplayName(const QString& name)
{
    Q_D(IrcConnection);
    if (d->displayName != name) {
        d->displayName = name;
        emit displayNameChanged(name);
    }
}

/*!
    \since 3.1

    This property holds arbitrary user data.

    \par Access functions:
    \li QVariantMap userData() const
    \li void setUserData(const QVariantMap& data)

    \par Notifier signal:
    \li void userDataChanged(const QVariantMap& data)
 */
QVariantMap IrcConnection::userData() const
{
    Q_D(const IrcConnection);
    return d->userData;
}

void IrcConnection::setUserData(const QVariantMap& data)
{
    Q_D(IrcConnection);
    if (d->userData != data) {
        d->userData = data;
        emit userDataChanged(data);
    }
}

/*!
    \property Status IrcConnection::status
    This property holds the connection status.

    \par Access function:
    \li Status status() const

    \par Notifier signal:
    \li void statusChanged(Status status)
 */
IrcConnection::Status IrcConnection::status() const
{
    Q_D(const IrcConnection);
    return d->status;
}

/*!
    \property bool IrcConnection::active
    This property holds whether the connection is active.

    The connection is considered active when its either connecting, connected or closing.

    \par Access function:
    \li bool isActive() const
 */
bool IrcConnection::isActive() const
{
    Q_D(const IrcConnection);
    return d->status == Connecting || d->status == Connected || d->status == Closing;
}

/*!
    \property bool IrcConnection::connected
    This property holds whether the connection has been established.

    The connection has been established when the welcome message
    has been received and the server is ready to receive commands.

    \sa Irc::RPL_WELCOME

    \par Access function:
    \li bool isConnected() const

    \par Notifier signal:
    \li void connected()
 */
bool IrcConnection::isConnected() const
{
    Q_D(const IrcConnection);
    return d->status == Connected;
}

/*!
    \property bool IrcConnection::enabled
    This property holds whether the connection is enabled.

    The default value is \c true.

    When set to \c false, a disabled connection does nothing when open() is called.

    \par Access functions:
    \li bool isEnabled() const
    \li void setEnabled(bool enabled) [slot]
    \li void setDisabled(bool disabled) [slot]

    \par Notifier signal:
    \li void enabledChanged(bool enabled)
 */
bool IrcConnection::isEnabled() const
{
    Q_D(const IrcConnection);
    return d->enabled;
}

void IrcConnection::setEnabled(bool enabled)
{
    Q_D(IrcConnection);
    if (d->enabled != enabled) {
        d->enabled = enabled;
        emit enabledChanged(enabled);
    }
}

void IrcConnection::setDisabled(bool disabled)
{
    setEnabled(!disabled);
}

/*!
    \property int IrcConnection::reconnectDelay
    This property holds the reconnect delay in seconds.

    A positive (greater than zero) value enables automatic reconnect.
    When the connection is lost due to a socket error, IrcConnection
    will automatically attempt to reconnect after the specified delay.

    The default value is \c 0 (automatic reconnect disabled).

    \par Access functions:
    \li int reconnectDelay() const
    \li void setReconnectDelay(int seconds)

    \par Notifier signal:
    \li void reconnectDelayChanged(int seconds)
 */
int IrcConnection::reconnectDelay() const
{
    Q_D(const IrcConnection);
    return d->reconnecter.interval() / 1000;
}

void IrcConnection::setReconnectDelay(int seconds)
{
    Q_D(IrcConnection);
    const int interval = qMax(0, seconds) * 1000;
    if (d->reconnecter.interval() != interval) {
        d->reconnecter.setInterval(interval);
        emit reconnectDelayChanged(interval);
    }
}

/*!
    \property int IrcConnection::connectionCount
    This property holds the amount of times a connection was established.

    The default value is \c 0 (no connections where established).

    \par Access functions:
    \li int connectionCount() const
 */
int IrcConnection::connectionCount() const
{
    Q_D(const IrcConnection);
    return d->connectionCount;
}

/*!
    This property holds the socket. The default value is an instance of QTcpSocket.

    The previously set socket is deleted if its parent is \c this.

    \note IrcConnection supports QSslSocket in the way that it automatically
    calls QSslSocket::startClientEncryption() while connecting.

    \par Access functions:
    \li \ref QAbstractSocket* socket() const
    \li void setSocket(\ref QAbstractSocket* socket)

    \sa IrcConnection::secure
 */
QAbstractSocket* IrcConnection::socket() const
{
    Q_D(const IrcConnection);
    return d->socket;
}

void IrcConnection::setSocket(QAbstractSocket* socket)
{
    Q_D(IrcConnection);
    if (d->socket != socket) {
        if (d->socket) {
            d->socket->disconnect(this);
            if (d->socket->parent() == this)
                d->socket->deleteLater();
        }

        d->socket = socket;
        if (socket) {
            connect(socket, SIGNAL(connected()), this, SLOT(_irc_connected()));
            connect(socket, SIGNAL(disconnected()), this, SLOT(_irc_disconnected()));
            connect(socket, SIGNAL(readyRead()), this, SLOT(_irc_readData()));
            connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(_irc_error(QAbstractSocket::SocketError)));
            connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(_irc_state(QAbstractSocket::SocketState)));
            if (isSecure())
                connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(_irc_sslErrors()));
        }
    }
}

/*!
    \property bool IrcConnection::secure
    This property holds whether the socket is an SSL socket.

    This property is provided for convenience. Calling
    \code
    connection->setSecure(true);
    \endcode

    is equivalent to:

    \code
    QSslSocket* socket = new QSslSocket(socket);
    socket->setPeerVerifyMode(QSslSocket::QueryPeer);
    connection->setSocket(socket);
    \endcode

    \note IrcConnection does not handle SSL errors, see
    QSslSocket::sslErrors() for more details on the subject.

    \par Access functions:
    \li bool isSecure() const
    \li void setSecure(bool secure)

    \par Notifier signal:
    \li void secureChanged(bool secure)

    \sa secureSupported, IrcConnection::socket
 */
bool IrcConnection::isSecure() const
{
#ifdef QT_NO_SSL
    return false;
#else
    return qobject_cast<QSslSocket*>(socket());
#endif // QT_NO_SSL
}

void IrcConnection::setSecure(bool secure)
{
#ifdef QT_NO_SSL
    if (secure) {
        qWarning("IrcConnection::setSecure(): the Qt build does not support SSL");
        return;
    }
#else
    if (secure && !QSslSocket::supportsSsl()) {
        qWarning("IrcConnection::setSecure(): the platform does not support SSL - try installing OpenSSL");
        return;
    }

    QSslSocket* sslSocket = qobject_cast<QSslSocket*>(socket());
    if (secure && !sslSocket) {
        sslSocket = new QSslSocket(this);
        sslSocket->setPeerVerifyMode(QSslSocket::QueryPeer);
        setSocket(sslSocket);
        emit secureChanged(true);
    } else if (!secure && sslSocket) {
        setSocket(new QTcpSocket(this));
        emit secureChanged(false);
    }
#endif // !QT_NO_SSL
}

/*!
    \deprecated Use Irc::isSecureSupported() instead.
 */
bool IrcConnection::isSecureSupported()
{
    return Irc::isSecureSupported();
}

/*!
    This property holds the used SASL (Simple Authentication and Security Layer) mechanism.

    \par Access functions:
    \li QString saslMechanism() const
    \li void setSaslMechanism(const QString& mechanism)

    \par Notifier signal:
    \li void saslMechanismChanged(const QString& mechanism)

    \sa supportedSaslMechanisms, \ref ircv3
 */
QString IrcConnection::saslMechanism() const
{
    Q_D(const IrcConnection);
    return d->saslMechanism;
}

void IrcConnection::setSaslMechanism(const QString& mechanism)
{
    Q_D(IrcConnection);
    if (!mechanism.isEmpty() && !supportedSaslMechanisms().contains(mechanism.toUpper())) {
        qWarning("IrcConnection::setSaslMechanism(): unsupported mechanism: '%s'", qPrintable(mechanism));
        return;
    }
    if (d->saslMechanism != mechanism) {
        if (isActive())
            qWarning("IrcConnection::setSaslMechanism() has no effect until re-connect");
        d->saslMechanism = mechanism.toUpper();
        emit saslMechanismChanged(mechanism);
    }
}

/*!
    \deprecated Use Irc::supportedSaslMechanisms() instead.
 */
QStringList IrcConnection::supportedSaslMechanisms()
{
    return Irc::supportedSaslMechanisms();
}

/*!
    \since 3.5

    This property holds CTCP (client to client protocol) replies.

    This is a convenient request-reply map for customized static
    CTCP replies. For dynamic replies, override createCtcpReply()
    instead.

    \note Set an empty reply to omit the automatic reply.

    \par Access functions:
    \li QVariantMap ctcpReplies() const
    \li void setCtcpReplies(const QVariantMap& replies)

    \par Notifier signal:
    \li void ctcpRepliesChanged(const QVariantMap& replies)

    \sa createCtcpReply()
 */
QVariantMap IrcConnection::ctcpReplies() const
{
    Q_D(const IrcConnection);
    return d->ctcpReplies;
}

void IrcConnection::setCtcpReplies(const QVariantMap& replies)
{
    Q_D(IrcConnection);
    if (d->ctcpReplies != replies) {
        d->ctcpReplies = replies;
        emit ctcpRepliesChanged(replies);
    }
}

/*!
    This property holds the network information.

    \par Access function:
    \li IrcNetwork* network() const
 */
IrcNetwork* IrcConnection::network() const
{
    Q_D(const IrcConnection);
    return d->network;
}

/*!
    Opens a connection to the server.

    The function does nothing when the connection is already \ref active
    or explicitly \ref enabled "disabled".

    \note The function merely outputs a warnings and returns immediately if
    either \ref host, \ref userName, \ref nickName or \ref realName is empty.
 */
void IrcConnection::open()
{
    Q_D(IrcConnection);
    if (d->host.isEmpty() && d->servers.isEmpty()) {
        qWarning("IrcConnection::open(): host is empty!");
        return;
    }
    if (d->userName.isEmpty()) {
        qWarning("IrcConnection::open(): userName is empty!");
        return;
    }
    if (d->nickName.isEmpty() && d->nickNames.isEmpty()) {
        qWarning("IrcConnection::open(): nickNames is empty!");
        return;
    }
    if (d->realName.isEmpty()) {
        qWarning("IrcConnection::open(): realName is empty!");
        return;
    }
    if (d->enabled && d->socket)
        d->open();
}

/*!
    Immediately closes the connection to the server.

    Calling close() makes the connection close immediately and thus might lead to
    "remote host closed the connection". In order to quit gracefully, call quit()
    first. This function attempts to flush the underlying socket, but this does
    not guarantee that the server ever receives the QUIT command if the connection
    is closed immediately after sending the command. In order to ensure a graceful
    quit, let the server handle closing the connection.

    C++ example:
    \code
    connection->quit(reason);
    QTimer::singleShot(timeout, connection, SLOT(deleteLater()));
    \endcode

    QML example:
    \code
    connection.quit(reason);
    connection.destroy(timeout);
    \endcode

    \sa quit()
 */
void IrcConnection::close()
{
    Q_D(IrcConnection);
    if (d->socket) {
        d->closed = true;
        d->pendingOpen = false;
        d->socket->flush();
        d->socket->abort();
        d->socket->disconnectFromHost();
        if (d->socket->state() == QAbstractSocket::UnconnectedState)
            d->setStatus(Closed);
        d->reconnecter.stop();
        d->setConnectionCount(0);
    }
}

/*!
    Sends a quit command with an optionally specified \a reason.

    This method is provided for convenience. It is equal to:
    \code
    if (connection->isActive())
        connection->sendCommand(IrcCommand::createQuit(reason));
    \endcode

    \sa IrcCommand::createQuit()
 */
void IrcConnection::quit(const QString& reason)
{
    if (isConnected())
        sendCommand(IrcCommand::createQuit(reason));
    else
        close();
}

/*!
    Sends a \a command to the server.

    If the connection is not active, the \a command is queued and sent
    later when the connection has been established.

    \note If the command has a valid parent, it is an indication that
    the caller of this method is be responsible for freeing the command.
    If the command does not have a valid parent (like the commands
    created via various IrcCommand::createXxx() methods) the connection
    will take ownership of the command and delete it once it has been
    sent. Thus, the command must have been allocated on the heap and
    it is not safe to access the command after it has been sent.

    \sa sendData()
 */
bool IrcConnection::sendCommand(IrcCommand* command)
{
    Q_D(IrcConnection);
    bool res = false;
    if (command) {
        bool filtered = false;
        IrcCommandPrivate::get(command)->connection = this;
        for (int i = d->commandFilters.count() - 1; !filtered && i >= 0; --i) {
            QObject* filter = d->commandFilters.at(i);
            IrcCommandFilter* commandFilter = qobject_cast<IrcCommandFilter*>(filter);
            if (commandFilter && !d->activeCommandFilters.contains(filter)) {
                d->activeCommandFilters.push(filter);
                filtered |= commandFilter->commandFilter(command);
                d->activeCommandFilters.pop();
            }
        }
        if (filtered) {
            res = false;
        } else {
            QTextCodec* codec = QTextCodec::codecForName(command->encoding());
            Q_ASSERT(codec);
            res = sendData(codec->fromUnicode(command->toString()));
        }
        if (!command->parent())
            command->deleteLater();
    }
    return res;
}

/*!
    Sends raw \a data to the server.

    \sa sendCommand()
 */
bool IrcConnection::sendData(const QByteArray& data)
{
    Q_D(IrcConnection);
    if (d->socket) {
        if (isActive()) {
            const QByteArray cmd = data.left(5).toUpper();
            if (cmd.startsWith("PASS "))
                ircDebug(this, IrcDebug::Write) << data.left(5) + QByteArray(data.mid(5).length(), 'x');
            else
                ircDebug(this, IrcDebug::Write) << data;
            if (!d->closed && data.length() >= 4) {
                if (cmd.startsWith("QUIT") && (data.length() == 4 || QChar(data.at(4)).isSpace())) {
                    d->closed = true;
                    d->setConnectionCount(0);
                }
            }
            return d->protocol->write(data);
        } else {
            d->pendingData += data;
        }
    }
    return false;
}

/*!
    Sends raw \a message to the server using UTF-8 encoding.

    \sa sendData(), sendCommand()
 */
bool IrcConnection::sendRaw(const QString& message)
{
    return sendData(message.toUtf8());
}

/*!
    Installs a message \a filter on the connection. The \a filter must implement the IrcMessageFilter interface.

    A message filter receives all messages that are sent to the connection. The filter
    receives messages via the \ref IrcMessageFilter::messageFilter() "messageFilter()"
    function. The function must return \c true if the message should be filtered,
    (i.e. stopped); otherwise it must return \c false.

    If multiple message filters are installed on the same connection, the filter
    that was installed last is activated first.

    \sa removeMessageFilter()
 */
void IrcConnection::installMessageFilter(QObject* filter)
{
    Q_D(IrcConnection);
    IrcMessageFilter* msgFilter = qobject_cast<IrcMessageFilter*>(filter);
    if (msgFilter) {
        d->messageFilters += filter;
        connect(filter, SIGNAL(destroyed(QObject*)), this, SLOT(_irc_filterDestroyed(QObject*)), Qt::UniqueConnection);
    }
}

/*!
    Removes a message \a filter from the connection.

    The request is ignored if such message filter has not been installed.
    All message filters for a connection are automatically removed
    when the connection is destroyed.

    \sa installMessageFilter()
 */
void IrcConnection::removeMessageFilter(QObject* filter)
{
    Q_D(IrcConnection);
    IrcMessageFilter* msgFilter = qobject_cast<IrcMessageFilter*>(filter);
    if (msgFilter) {
        d->messageFilters.removeAll(filter);
        disconnect(filter, SIGNAL(destroyed(QObject*)), this, SLOT(_irc_filterDestroyed(QObject*)));
    }
}

/*!
    Installs a command \a filter on the connection. The \a filter must implement the IrcCommandFilter interface.

    A command filter receives all commands that are sent from the connection. The filter
    receives commands via the \ref IrcCommandFilter::commandFilter() "commandFilter()"
    function. The function must return \c true if the command should be filtered,
    (i.e. stopped); otherwise it must return \c false.

    If multiple command filters are installed on the same connection, the filter
    that was installed last is activated first.

    \sa removeCommandFilter()
 */
void IrcConnection::installCommandFilter(QObject* filter)
{
    Q_D(IrcConnection);
    IrcCommandFilter* cmdFilter = qobject_cast<IrcCommandFilter*>(filter);
    if (cmdFilter) {
        d->commandFilters += filter;
        connect(filter, SIGNAL(destroyed(QObject*)), this, SLOT(_irc_filterDestroyed(QObject*)), Qt::UniqueConnection);
    }
}

/*!
    Removes a command \a filter from the connection.

    The request is ignored if such command filter has not been installed.
    All command filters for a connection are automatically removed when
    the connection is destroyed.

    \sa installCommandFilter()
 */
void IrcConnection::removeCommandFilter(QObject* filter)
{
    Q_D(IrcConnection);
    IrcCommandFilter* cmdFilter = qobject_cast<IrcCommandFilter*>(filter);
    if (cmdFilter) {
        d->commandFilters.removeAll(filter);
        disconnect(filter, SIGNAL(destroyed(QObject*)), this, SLOT(_irc_filterDestroyed(QObject*)));
    }
}

/*!
    \since 3.1

    Saves the state of the connection. The \a version number is stored as part of the state data.

    To restore the saved state, pass the return value and \a version number to restoreState().
 */
QByteArray IrcConnection::saveState(int version) const
{
    Q_D(const IrcConnection);
    QVariantMap args;
    args.insert("version", version);
    args.insert("host", d->host);
    args.insert("port", d->port);
    args.insert("servers", d->servers);
    args.insert("userName", d->userName);
    args.insert("nickName", d->nickName);
    args.insert("realName", d->realName);
    args.insert("password", d->password);
    args.insert("nickNames", d->nickNames);
    args.insert("displayName", displayName());
    args.insert("userData", d->userData);
    args.insert("encoding", d->encoding);
    args.insert("enabled", d->enabled);
    args.insert("reconnectDelay", reconnectDelay());
    args.insert("secure", isSecure());
    args.insert("saslMechanism", d->saslMechanism);

    QByteArray state;
    QDataStream out(&state, QIODevice::WriteOnly);
    out << args;
    return state;
}

/*!
    \since 3.1

    Restores the \a state of the connection. The \a version number is compared with that stored in \a state.
    If they do not match, the connection state is left unchanged, and this function returns \c false; otherwise,
    the state is restored, and \c true is returned.

    \sa saveState()
 */
bool IrcConnection::restoreState(const QByteArray& state, int version)
{
    Q_D(IrcConnection);
    if (isActive())
        return false;

    QVariantMap args;
    QDataStream in(state);
    in >> args;
    if (in.status() != QDataStream::Ok || args.value("version", -1).toInt() != version)
        return false;

    setHost(args.value("host", d->host).toString());
    setPort(args.value("port", d->port).toInt());
    setServers(args.value("servers", d->servers).toStringList());
    setUserName(args.value("userName", d->userName).toString());
    setNickName(args.value("nickName", d->nickName).toString());
    setRealName(args.value("realName", d->realName).toString());
    setPassword(args.value("password", d->password).toString());
    setNickNames(args.value("nickNames", d->nickNames).toStringList());
    if (!d->nickNames.isEmpty() && d->nickNames.indexOf(d->nickName) != 0)
        setNickName(d->nickNames.first());
    setDisplayName(args.value("displayName").toString());
    setUserData(args.value("userData", d->userData).toMap());
    setEncoding(args.value("encoding", d->encoding).toByteArray());
    setEnabled(args.value("enabled", d->enabled).toBool());
    setReconnectDelay(args.value("reconnectDelay", reconnectDelay()).toInt());
    setSecure(args.value("secure", isSecure()).toBool());
    setSaslMechanism(args.value("saslMechanism", d->saslMechanism).toString());
    return true;
}

/*!
    Creates a reply command for the CTCP \a request.

    The default implementation first checks whether the \ref ctcpReplies
    property contains a user-supplied reply for the request. In case it
    does, the reply is sent automatically. In case there is no user-supplied
    reply, the default implementation handles the following CTCP requests:
    CLIENTINFO, PING, SOURCE, TIME and VERSION.

    Reimplement this function in order to alter or omit the default replies.

    \sa ctcpReplies
 */
IrcCommand* IrcConnection::createCtcpReply(IrcPrivateMessage* request) const
{
    Q_D(const IrcConnection);
    QString reply;
    QString type = request->content().split(" ", Qt::SkipEmptyParts).value(0).toUpper();
    if (d->ctcpReplies.contains(type))
        reply = type + QLatin1String(" ") + d->ctcpReplies.value(type).toString();
    else if (type == "PING")
        reply = request->content();
    else if (type == "TIME")
        reply = QLatin1String("TIME ") + QLocale().toString(QDateTime::currentDateTime(), QLocale::ShortFormat);
    else if (type == "VERSION")
        reply = QLatin1String("VERSION Communi ") + Irc::version() + QLatin1String(" - https://communi.github.io");
    else if (type == "SOURCE")
        reply = QLatin1String("SOURCE https://communi.github.io");
    else if (type == "CLIENTINFO")
        reply = QLatin1String("CLIENTINFO PING SOURCE TIME VERSION");
    if (!reply.isEmpty())
        return IrcCommand::createCtcpReply(request->nick(), reply);
    return nullptr;
}

/*!
    \since 3.2

    This property holds the protocol.

    The previously set protocol is deleted if its parent is \c this.

    \par Access functions:
    \li \ref IrcProtocol* protocol() const
    \li void setProtocol(\ref IrcProtocol* protocol)
 */
IrcProtocol* IrcConnection::protocol() const
{
    Q_D(const IrcConnection);
    return d->protocol;
}

void IrcConnection::setProtocol(IrcProtocol* proto)
{
    Q_D(IrcConnection);
    if (d->protocol != proto) {
        if (d->protocol && d->protocol->parent() == this)
            delete d->protocol;
        d->protocol = proto;
    }
}

#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, IrcConnection::Status status)
{
    const int index = IrcConnection::staticMetaObject.indexOfEnumerator("Status");
    QMetaEnum enumerator = IrcConnection::staticMetaObject.enumerator(index);
    const char* key = enumerator.valueToKey(status);
    debug << (key ? key : "Unknown");
    return debug;
}

QDebug operator<<(QDebug debug, const IrcConnection* connection)
{
    if (!connection)
        return debug << "IrcConnection(0x0) ";
    debug.nospace() << connection->metaObject()->className() << '(' << (void*) connection;
    if (!connection->displayName().isEmpty())
        debug.nospace() << ", " << qPrintable(connection->displayName());
    debug.nospace() << ')';
    return debug.space();
}
#endif // QT_NO_DEBUG_STREAM

#include "moc_ircconnection.cpp"

IRC_END_NAMESPACE

redpajama_set_name: RedPajamaGithub